hibernate关系映射,一对多,多对多,以及session方法简介

注意:

使用集合属性时,一定要使用接口,而不能声明为具体的实现类。
因为经过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();
		
	}
}


你可能感兴趣的:(hibernate关系映射,一对多,多对多,以及session方法简介)