注意:
使用集合属性时,一定要使用接口,而不能声明为具体的实现类。
因为经过Session操作后,集合就变成了Hibernate自己的集合实现类。
另外:无序集合是可以排序的sort属性默认为unsorted;sort="unsorted|natural|comparatorClass"
:指定排序,这是在内存中排序,效率较低,一般不使用
order-by属性:写的是order by 子句,是SQL语句,是操作的集合表。
这是在查询数据时指定orderby子句,效率高,经常使用。
lazy建议为false对集合属性设置懒加载,这样可以减少查询数据的次数,只有在需要集合元素时才会真正查询数据库
Session常用方法统讲,以及hibernate中对象状态的改变:
============================
对象的状态:
临时状态:
与数据库没有对应,跟Session没有关联。
一般是新new出的对象。
持久化状态:
对象在Session的管理之中,最终会有对应的数据库记录。
特点:
1,有OID
2,对对象的修改会同步到数据库。
游离状态:
数据库中有对应记录,但对象不在Session管理之中。
修改此状态对象时数据库不会有变化。
删除状态:
执行了delete()后的对象。
===============================
一、操作实体对象的
save():保存对象
update()
// update():把游离状态变为持久化状态
// 会生成:update ...
// 在更新时,对象不存在就报错
saveOrUpdate()
// saveOrUpdate():把临时或游离状态转为持久化状态
// 会生成:insert into 或 update ...
// 在更新时,对象不存在就报错
// 本方法是根据id判断对象是什么状态的:如果id为原始值(对象的是null,原始类型数字是0)就是临时状态,如果不是原始值就是游离状态。
delete()
// delete():把持久化或游离转为删除状态
// 会生成:delete ...
// 如果删除的对象不存在,就会抛异常
二、操作缓存的
clear():把session中所有对象从持久态变成游离态
evict():把session中单个对象从持久态变成游离态
flush()
// 操作大量数据,要防止Session中对象过多而内存溢出
所以我们要在内存之前执行
session.flush();
session.clear();
先把session中数据同步到数据库中,然后清空session缓存
三、查询实体对象的
get()
load()
createQuery()://hql语句
createCriteria():面向对象方式的
// load():获取数据,是持久化状态
// 会生成:select ... where id=?
// load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
// 让懒加载失效的方式:一、把实体写成final的;二、在hbm.xml中写<class ... lazy="false">
// 不会马上执行sql语句,而是在第1次使用非id或class属性时执行sql。
// 如果数据不存在,就抛异常:ObjectNotFoundException
加载方式 返回值如果数据不存在
---------------------------------------------------------
get 立即加载
真实对象或null 返回null
load 延迟加载代理对象
抛异常
hibernate映射关系:
双向关联
单向关联:
单向多对一
单向一对多
单向多对多
一对一
单向在这里不在赘述,只需在双向的基础上修改配置即可:
讲解介绍都在代码中:
现实世界的关系映射大概是三种,一对一,一对多,多对多,单向和双向映射,这里只介绍双向,单向只需在双向的基础上修改即可:
数据库连接配置清单:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 指定方言,指定mysql ,建议配置成上面,不然hibernate在执行创建表的时候会报错,目前没有找到原因-->
<property name="hbm2ddl.auto">update</property><!-- -这个参数指定,hibernate可以更新数据,当为create时,hibernate每次执行插入操作都会先删除表,然后在创建表插入数据 -->
<property name="show_sql">true</property><!-- -这个参数,表示,hibernate会把自动生成的参数,显示在控制台给我们看,一般用于开发阶段 -->
<!-- <mapping resource="com/leige/domain/User.hbm.xml"/> --><!-- -指定映射文件,告诉hibernate,对象与表的映射关系 -->
</session-factory>
</hibernate-configuration>
一:一对多映射(这里采用的事经典的员工部门例子):
部门类(Department)和部门表的(Department.hbm.xml)xml配置文件:
Department:
package hibernate_oneToMany;
import java.util.HashSet;
import java.util.Set;
public class Department {
private Integer id;
private String name;
private Set<Employee> employees=new HashSet<Employee>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
Department.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-2 13:39:24 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_oneToMany">
<class name="Department" table="department">
<id name="id" type="int">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="name" />
</property>
<!-- 对于部门来说,要存储多个员工,需采用集合表示 ,配置和普通集合差不多
inerse:属性
默认为false:表示本方维护关联关系
true:表示本方放弃维护
只是影响是否能设置外键列的值(设成有效值或是null值),对获取信息没有影响。
class:表示关联的实体类型,如果不在同一个包下,请使用全限定名
cascade属性:
默认为none,代表不级联。
级联是指操作主对象时,对关联的对象也做相同的操作。
可设为:delete, save-update, all, none ...
设置为delete表示删除部门时,部门下的所有员工也会删除
-->
<set name="employees" inverse="true" cascade="delete">
<key>
<column name="departID" />
</key>
<!-- 多对一:,部门员工,对于部门来说一对多,所以使用 one-to-many标签,直接写要对应的类即可 ,因为hibernate
可以通过映射找到类,进而找到表的名称,不写也可以-->
<one-to-many class="Employee" />
</set>
</class>
</hibernate-mapping>
员工类(Employee)和部门表的(Employee.hbm.xml)xml配置文件:Employee:
package hibernate_oneToMany;
public class Employee {
private Integer id;
private String name;
private Department department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
Employee.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-2 13:39:24 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_oneToMany">
<class name="Employee" table="employees">
<id name="id" type="int">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="name" />
</property>
<!-- 一对多: 对于员工来说:多对一,所以使用many-to-one 指定要对应的类和数据库数据库中药显示的列的名称,
该名称的内容是被引用的外键值,在这里就是部门ID
注意many-to-one引用的是集合的Department的主键,当Department中集合外键是Department中的主键时,注意二者要为一致
-->
<many-to-one name="department" class="Department" >
<column name="departID" />
</many-to-one>
</class>
</hibernate-mapping>
测试操作类:package hibernate_oneToMany;
import hibernate_manyeToMany.Student;
import hibernate_manyeToMany.Teacher;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* @author 梁磊
*
*/
public class App {
static SessionFactory sessionFactory;
static{
//初始化数据
sessionFactory=new Configuration().configure()
.addClass(Department.class).addClass(Employee.class)
.buildSessionFactory();
}
@Test
public void testSave() {
Session session=sessionFactory.openSession();
session.beginTransaction();
//实例对象
Employee employee1=new Employee();
Employee employee2=new Employee();
employee1.setName("leige");
employee2.setName("leige2");
Department department=new Department();
department.setName("开发部");
//关联起来
department.getEmployees().add(employee2);
department.getEmployees().add(employee1);
employee1.setDepartment(department);
employee2.setDepartment(department);
//保存时建议报没有外键的一方放在前面,这与数据库外键有关,不会生成update语句
session.save(department);
session.save(employee1);
session.save(employee2);
session.getTransaction().commit();
}
@Test
public void testGet() {
//测试获取一方,获取查出另一方
//查询部门,获取员工
/*Session session=sessionFactory.openSession();
session.beginTransaction();
Department department=(Department) session.get(Department.class, 1);
System.out.println(department);
System.out.println(department.getEmployees());
session.getTransaction().commit();*/
//获取员工查询,部门
Session session=sessionFactory.openSession();
session.beginTransaction();
Employee employee=(Employee) session.get(Employee.class, 1);
session.getTransaction().commit();
System.out.println(employee);
System.out.println(employee.getDepartment());
}
/**
* 测试解除关联关系
*/
@Test
public void testRemove() {
//解除关系时先get在解除
Session session=sessionFactory.openSession();
session.beginTransaction();
//解除部门下的所有员工,这个操作与inverse属性有关,由于Department不维护关系,所以无法从部门方解除所有员工
/*
* Department department=(Department) session.get(Department.class, 1);
* department.getEmployees().clear();
session.getTransaction().commit();*/
//但是要想解除所有员工,只能从维护关系的一方解除,这里是解除,不是删除,(解除是解除关联关系,删除是删除数据)
//所以操作为
List<Employee> employees=session.createQuery("from Employee where departID=1").list();
for(Employee em:employees)
em.setDepartment(null);
session.getTransaction().commit();
}
/**
* 测试删除一方
*/
@Test
public void testDelete() {
//删除对象首先获取对象
Session session=sessionFactory.openSession();
session.beginTransaction();
//删除部门,这个操作与inverse属性有关,本例由于Department不维护关系,所以无法删除部门有员工的部门,因为有外键的引用
//所以只能删除空部门,
/* Department department=(Department) session.get(Department.class, 1);
session.delete(department);
session.getTransaction().commit();*/
//删除员工,删除有外键的一方和外键方没有关系
Employee employee=(Employee) session.get(Employee.class, 1);
session.delete(employee);
session.getTransaction().commit();
}
}
各位初学者,可以试着测试,可以得到想要的,结果,一定要学会看异常信息
二:多对多映射本例采用学生老师集合映射:
Teacher和Teacher.hbm.xml文件如下:
Teacher:
package hibernate_manyeToMany;
import java.util.HashSet;
import java.util.Set;
public class Teacher {
private int id;
private String name;
private Set<Student> students=new HashSet<Student>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
}
Teacher.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-2 17:09:56 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_manyeToMany">
<class name="Teacher" table="teacher">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="name" />
</property>
<!-- 多对多关系,处于对hibernate自动生成sql语句优化的考虑,建议设置一方维护,
例如本例中应该设置学生维护关系,比较符合实际,
所以Teacher中设置inverse为true,表示本方放弃维护关系
student中inverse为false,表示本方维护关系 ,-->
<set name="students" table="teacher_student" inverse="true" lazy="true">
<key>
<column name="teacherID" />
</key>
<many-to-many class="Student" column="studentID"></many-to-many>
</set>
</class>
</hibernate-mapping>
Student和Student.hbm.xml
Student:
package hibernate_manyeToMany;
import java.util.HashSet;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set<Teacher> teachaers=new HashSet<Teacher>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Teacher> getTeachaers() {
return teachaers;
}
public void setTeachaers(Set<Teacher> teachaers) {
this.teachaers = teachaers;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-2 17:09:56 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_manyeToMany">
<class name="Student" table="student">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="name" />
</property>
<!-- 多对多关系,处于对hibernate自动生成sql语句优化的考虑,建议设置一方维护,
例如本例中应该设置学生维护关系,比较符合实际,
所以Teacher中设置inverse为true,表示本方放弃维护关系
student中inverse为false,表示本方维护关系,
另外:无序集合是可以排序的sort属性sort="unsorted|natural|comparatorClass"
:指定排序,这是在内存中排序,效率较低,一般不使用
order-by属性:写的是order by 子句,是SQL语句,是操作的集合表。
这是在查询数据时指定orderby子句,效率高,经常使用。
lazy建议为false对集合属性设置懒加载,这样可以减少查询数据的次数,只有在需要集合元素时才会真正查询数据库 -->
<set name="teachaers" table="teacher_student" inverse="false" lazy="false" sort="unsorted" order-by="name desc">
<key>
<column name="studentID" />
</key>
<many-to-many class="Teacher" column="teacherID"></many-to-many>
</set>
</class>
</hibernate-mapping>
测试操作类:
package hibernate_manyeToMany;
import hibernate_collection.User;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* @author 梁磊
*
*/
public class App {
static SessionFactory sessionFactory;
static{
//初始化数据
sessionFactory=new Configuration().configure()
.addClass(Student.class).addClass(Teacher.class)
.buildSessionFactory();
}
/**
* 测试保存
*/
@Test
public void testSave() {
Teacher teacher1=new Teacher();
//新建对象
Teacher teacher2=new Teacher();
teacher1.setName("找老师");
teacher2.setName("梁老师");
Student student1=new Student();
Student student2=new Student();
student1.setName("student1");
student2.setName("学生2");
//关联起来
//老师关联学生
teacher1.getStudents().add(student1);
teacher1.getStudents().add(student2);
teacher2.getStudents().add(student2);
teacher2.getStudents().add(student1);
//学生关联老师
student1.getTeachaers().add(teacher1);
student1.getTeachaers().add(teacher2);
student2.getTeachaers().add(teacher2);
student2.getTeachaers().add(teacher1);
//保存对象
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(teacher2);
session.save(teacher1);
session.save(student1);
session.save(student2);
session.getTransaction().commit();
}
/**
* 测试获取
*/
@Test
public void testGet() {
//
Session session=sessionFactory.openSession();
session.beginTransaction();
//获取是与inverse属性无关,不管是否维护关系都能一方获取另一方的数据
//获取老师显示学生
Teacher teacher=(Teacher) session.get(Teacher.class, 1);
System.out.println(teacher);
System.out.println(teacher.getStudents());
//获取学生显示老师
Student student=(Student) session.get(Student.class, 1);
System.out.println(student);
System.out.println(student.getTeachaers());
session.getTransaction().commit();
}
/**
* 测试解除关联关系
*/
@Test
public void testRemove() {
Session session=sessionFactory.openSession();
session.beginTransaction();
//测试解除学生关系,不会产生效果,不会执行sql语句,因为,Teacher对象不维护关系,即inverse属性为true
Teacher teacher=(Teacher) session.get(Teacher.class, 1);
teacher.getStudents().clear();
//测试学生和老师解除关系
/* Student student=(Student) session.get(Student.class, 1);
student.getTeachaers().clear();*/
session.getTransaction().commit();
}
/**
* 测试删除一方
*/
@Test
public void testDelete() {
Session session=sessionFactory.openSession();
session.beginTransaction();
//测试删除老师,会报错,因为老师方设置inverse属性为true,不维护关系,所以会执行sql语句,但是因为有外键引用所以会产生sql异常
/*Teacher teacher=(Teacher) session.get(Teacher.class, 1);
session.delete(teacher);*/
//测试删除学生,会成功,因为学生维护关系,会删除学生表中记录,然后删除中间表teacher_student中记录
Student student=(Student) session.get(Student.class, 1);
session.delete(student);
session.getTransaction().commit();
}
}