Hibernate总结(四)--session的产生方式和一对多的关系映射

一、session的创建

Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,但Session不是线程安全的。


每次openSession,产生的都是一个新的session,相当于创建一个新的连接。但是有很多时候,并不希望这样。比如在淘宝购物,在付账的一瞬间,至少有三件事情发生,转账,仓库数据变化,购物历史记录。而这三件事有必须在同一事务下。自然我们会联想都ThreadLocal<Session> 来解决这个问题。

Hibernate提供了getCurrentSession()方法来解决这一问题,详细看ThreadLocalSessionContext类源码


思考:为什么ThreadLocal(context)里放的是Map,且Map的key是sessionFactory,value是session?

1.一个sessionFactory代表一个数据库连接,这样Map的key存放sessionFactory肯定也就是一个(对于一个数据库),自然也就是一个session,而使用Map也就是为了多个数据库连接。

2.在web操作时希望 request 和 response 是一个连接,这样设计保证了这点,无论怎么误操作,即使又新建了一个session,但是sessionfatory不变,也只会把原理的session覆盖,还是保证了在一个session里。

这样的做法,起到了一个双保险的作用,IBM以前就是ThreadLocal<Session>。

getCurrentSession使用

在hibernate.cfg.xml中添加

[html]   view plain  copy
  1. <property name="current_session_context_class">thread</property>  

注意:如果用该方法(当前线程先产生session),CRUD必须都在事务下进行,在transaction.commit()时,session自动关闭。

缺点:把session和transaction绑定在一起了.在transaction提交之后,再想进行数据库操作就不行了(工作流)

Spring与Hibernate结合后,就把这个提交方式改了,事务提交与session关闭分开。

二、onetomany 一对多关系映射

//Classes类

public class Classes implements Serializable{
    private Long cid; //标示符属性
    private String name;  //一般属性
    private String description;
private Set<Student> students;  //关联对象
    
//Stduent类
public class Student implements Serializable{
    private Long sid;
    private String name;
    private String description;
 

//Classes.hbm.xml
<hibernate-mapping>
    <class name="com.itheima12.hibernate.domain.Classes">
        <id name="cid" length="5">
            <generator class="increment"></generator>
        </id>
        <property name="description" length="50"></property>
        <property name="name" length="20"></property>
        <!-- 
            set元素针对的就是Classes类中的Set属性
            cascade  级联操作
               null  默认值
               save-update
                      在保存classes对象的时候,针对student进行保存或者更新的操作
                      在更新classes对象的时候,针对student进行保存或者更新的操作
               all
               delete
            inverse  关系操作
               default:classes维护classes与student之间的关系
               true:   classes不维护classes与student之间的关系
               false:  classes维护classes与student之间的关系
         -->
        <set name="students" cascade="save-update" inverse="true">
            <!-- 
                外键
                       告诉hibernate,通过cid就可以建立classes与student之间的关联
             -->
            <key>
                <column name="cid"></column>
            </key>
            <!-- 
                告诉hibernate,Classes类中的set集合中存放的是哪个元素
             -->
            <one-to-many class="com.itheima12.hibernate.domain.Student"/>
        </set>
    </class>
</hibernate-mapping>

<pre name="code" class="html">//Student.hbm.xml
<hibernate-mapping>
    <class name="com.itheima12.hibernate.domain.Student">
        <id name="sid" length="5">
            <generator class="increment"></generator>
        </id>
        <property name="description" length="50"></property>
        <property name="name" length="20"></property>
        
    </class>
</hibernate-mapping>


 
 
 
测试代码: 

/**
 * 一对多的单项
 * @author zd
 *				一般操作
				1、保存班级
				2、保存学生
				3、保存班级,保存学生

				级联操作
				4、保存班级级联保存学生
				5、保存班级级联更新学生
				6、更新班级级联保存学生
				7、更新班级级联更新学生
				8、删除班级级联删除学生
				9、在班级有级联save-update的情况下,从关联得到学生,并且删除学生?

				关系操作
				8、已经存在一个班级,新建一个学生,把该学生加入到该班级(建立关系操作)
				9、已经存在一个学生,新建一个班级,把该学生加入到该班级(建立关系操作)
				10、已经存在一个学生,已经存在一个班级,把该学生加入到该班级
				11、已经存在一个学生,把一个学生从一个班级转移到另外一个班级
				
				在一的一方维护关系的时候,总会发出维护关系的update语句,该update语句就是更新外键

				级联和关系的混合:
				12、在删除班级的时候,解除班级和学生之间的关系
 */
public class OneToManySingleTest extends HibernateUtils{
	
	//保存班级
	@Test
	public void testSaveClasses(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setName("黑马JavaEE+hadoop的12期");
		classes.setDescription("牛");
		session.save(classes);//需要设置cascade  
		transaction.commit();
	}
	//保存学生
	@Test
	public void testSaveStudent(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Student student = new Student();
		student.setName("班长");
		student.setDescription("带头大哥");
		session.save(student);
		transaction.commit();
	}
	//保存班级和学生
	@Test
	public void testSaveClassesAndSaveStudent(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setName("黑马视频班");
		classes.setDescription("野牛");
		
		Student student = new Student();
		student.setName("班秘");
		student.setDescription("凤姐");
		
		session.save(classes);
		session.save(student);
		transaction.commit();
	}
	
	/**
	 * 在保存班级的时候,级联保存学生
	 */
	@Test
	public void testSaveClasses_Cascade_Save_Student(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setName("黑马视频班");
		classes.setDescription("野牛");
		
		Student student = new Student();
		student.setName("班秘");
		student.setDescription("凤姐");
		
		//建立classes与student之间的关联
		Set<Student> students = new HashSet<Student>();
		students.add(student);
		classes.setStudents(students);
		
		session.save(classes); //显示保存,把保存student称为隐式保存//需要设置cascade  
		transaction.commit();
	}
	
	/**
	 * 在更新班级的时候,级联更新学生
	 * sessin.flush的时候
	 *    1、检查一级缓存中所有的持久化状态的对象
	 *        判断发出insert语句或者update语句
	 *    2、检查所有的持久化对象的关联对象
	 *         如果关联对象是由临时状态转化过来的,则对关联对象发出insert语句
	 *         如果关联对象是从数据库中提取出来的,则对照副本,决定是否发出update语句
	 */
	@Test
	public void testUpdateClasses_Cascade_Update_Student(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 2L);//持久化类
		Set<Student> students = classes.getStudents();//持久化类   
		for (Student student : students) {//把每一个student对象(关联对象)也放入到了一级缓存中
			student.setDescription("bb");
		}
		transaction.commit();
	}
	
	/**
	 * 在更新班级的时候,添加学生
	 */
	@Test
	public void testUpdateClasses_Cascade_Save_Student(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		/*
		 * 给cid为2的班级添加一个学生
		 */
		Classes classes = (Classes)session.get(Classes.class, 2L);		
		Student student = new Student();
		student.setName("美女1");
		student.setDescription("小林志玲");
		
		/**
		 * 建立班级与学生的关联
		 */
		classes.getStudents().add(student);
		
		transaction.commit();
	}
	
	/**
	 * 在更新班级的时候,级联保存学生,并且维护关系
	 * 	Hibernate: 
		    select
		        classes0_.cid as cid0_0_,
		        classes0_.description as descript2_0_0_,
		        classes0_.name as name0_0_ 
		    from
		        Classes classes0_ 
		    where
		        classes0_.cid=?
		Hibernate: 
		    select
		        students0_.cid as cid0_1_,
		        students0_.sid as sid1_,
		        students0_.sid as sid1_0_,
		        students0_.description as descript2_1_0_,
		        students0_.name as name1_0_ 
		    from
		        Student students0_ 
		    where
		        students0_.cid=?
		Hibernate: 
		    select
		        max(sid) 
		    from
		        Student
		Hibernate: 
		           因为在Classes.hbm.xml文件中设置了级联
		         <set name="students" cascade="save-update">
		    insert 
		    into
		        Student
		        (description, name, sid) 
		    values
		        (?, ?, ?)
		Hibernate: 
		           因为在Classes.hbm.xml文件中,inverse没有写,默认classes维护classes与student之间的关系
		           所以发出了更新关系的update语句
		           如果写了那么只是插入,并没有更新语句,没有关联关系(cid=null)
		    update
		        Student 
		    set
		        cid=? 
		    where
		        sid=?
	 */
	@Test
	public void testUpdateClasses_Cascade_Save_Student_Inverse(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		/*
		 * 给cid为2的班级添加一个学生
		 */
		Classes classes = (Classes)session.get(Classes.class, 2L);
		
		Student student = new Student();
		student.setName("美女1");
		student.setDescription("小林志玲");
		
		/**
		 * 建立班级与学生的关联
		 */
		classes.getStudents().add(student);
		
		transaction.commit();
	}
	
	/**
	 * 已经存在一个班级cid为1,已经存在一个学生,已经存在另外一个班级cid为2,该学生从cid为1的班级转到cid为2的班级
	 */
	@Test
	public void testTransform(){
		/**
		 * 1、把cid为1,2和sid为1的对象提取出来
		 */
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//Classes classes1 = (Classes)session.get(Classes.class, 1L);
		Classes classes2 = (Classes)session.get(Classes.class, 2L);//发出查询的sql语句
		Student student = (Student)session.get(Student.class, 1L);//发出查询的sql语句
		
		//解除 classes1与student之间的关系
		//classes1.getStudents().remove(student);
		//建立classes2与student之间的关系
		classes2.getStudents().add(student);
		transaction.commit();
	}
	
	/**
	 * 解除该班级和该班级中的所有的学生之间的关系
	 */
	@Test
	public void testRealseR(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		/**
		 * 解除cid为2的班级和所有的学生之间的关系
		 */
		Classes classes = (Classes)session.get(Classes.class,2L);
		classes.setStudents(null);
		transaction.commit();
	}
	
	/**
	 * 解除该班级和所有的学生之间的关系,再建立该班级和一些学生之间的关系
	 */
	@Test
	public void testRealseAllR_BuildSomeR(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//解除cid为2的班级和所有的学生之间的关系
		Classes classes = (Classes)session.get(Classes.class, 2L);
		classes.setStudents(null);
		
		Student student1 = new Student();
		student1.setName("王二麻子");
		
		Student student2 = new Student();
		student2.setName("隔壁老李");
		Set<Student> students = new HashSet<Student>();
		students.add(student2);
		students.add(student1);
		classes.setStudents(students);
		
		transaction.commit();
	}
	
	/**
	 * 删除一个班级
	 *   在删除班级之前,解除班级和学生之间的关系
	 *   Hibernate: 
		    select
		        classes0_.cid as cid0_0_,
		        classes0_.description as descript2_0_0_,
		        classes0_.name as name0_0_ 
		    from
		        Classes classes0_ 
		    where
		        classes0_.cid=?
		Hibernate: 
		           因为classes负责维护关系,所以该语句就是解除关系的sql语句
		    update
		        Student 
		    set
		        cid=null 
		    where
		        cid=?
		Hibernate: 
		    delete 
		    from
		        Classes 
		    where
		        cid=?

	 */
	@Test
	public void testDeleteClasses_1(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 1L);
		session.delete(classes);
		transaction.commit();
	}
	
	/**
	 * 在 Classes.hbm.xml文件中
	 *     <set name="students" cascade="all">
	 *     在删除班级的时候,级联删除学生
	 */
	@Test
	public void testDeleteClasses_2(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 1L);
		session.delete(classes);
		transaction.commit();
	}
	
	/**
	 * 删除一个学生,但是该学生必须从班级中提取出来
	 *   因为在Classes.hbm.xml文件中
	 *   	<set name="students" cascade="save-update">
	 *      classes针对student是关联的
	 *      而程序中的student对象是从classes中提取出来的关联对象,所以不能删除
	 */
	@Test
	public void testError(){
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 1L);
		Set<Student> students = classes.getStudents();
		//classes.setStudents(null);//解除关系
		for (Student student : students) {
			session.delete(student);
		}
		transaction.commit();
	}


双向:


//Student类添加一个private Classes classes;//关联对象

public class Student implements Serializable{
    private Long sid;
    private String name;
    private String description;
    private Classes classes;//关联对象
//测试代码

public class One2manyTest {  
  
    private Session session;  
    private Transaction transaction;  
      
    @Before  
    public void init(){  
        session = HibernateUtils.openSession();  
        transaction = session.beginTransaction();  
    }  
      
    /** 
     * Hibernate:  
        insert  
        into 
            STUDENT 
            (name, cid)  
        values 
            (?, ?) 
            连带cid直接插进去,所以如果用多的一个方,来维护关系,操作就是本身,没有维护外键一说 
     */  
    @Test  
    public void testSaveStudent_cascade_SaveClasses(){  
        Student student = new Student();  
        student.setName("haha");  
        Classes classes = new Classes();  
        classes.setName("软件1302");  
          
        //通过学生建立关系  
        student.setClasses(classes);//注意给Student设置cascade  
          
        session.save(student);  
    }  
      
    /** 
     * 把sid为3的学生,从cid为3的班级转到cid为4的班级 
     * Hibernate:  
        update 
            STUDENT  
        set 
            name=?, 
            cid=?  
        where 
            sid=? 
     */  
    @Test  
    public void testTransformClasses(){  
        Student student = (Student) session.get(Student.class, 3L);  
        Classes classes = (Classes) session.get(Classes.class, 4L);  
        student.setClasses(classes);  
        //session.update(student);  
    }  
  
    //移除一个班级的学生  
    @Test  
    public void testRemoveStudentFromClasses1(){  
        Student student = (Student) session.get(Student.class, 7L);  
        Classes classes = (Classes) session.get(Classes.class,3L);  
        Set<Student> students = classes.getStudents();  
        students.remove(student);//并没有删除,这里需要注意,因为此时是由多的一方维护关联关系,一的一方维护失效  
        session.update(classes);  
          
    }  
    @Test  
    public void testRemoveStudentFromClasses2(){  
        Student student = (Student) session.get(Student.class, 7L);  
        Classes classes = (Classes) session.get(Classes.class,3L);  
        student.setClasses(null);  
          
    }  
      
    @After  
    public void destory(){  
        transaction.commit();  
        session.close();  
    }  
}  



<p style=""><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="line-height:26px"><strong><strong style=""><span style="font-family:KaiTi_GB2312;font-size:18px;color:#ff00;">
</span></strong></strong></span></span></p><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="line-height:26px"></span></span>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值