一、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中添加
<property name="current_session_context_class">thread</property>
缺点:把session和transaction绑定在一起了.在transaction提交之后,再想进行数据库操作就不行了(工作流)
Spring与Hibernate结合后,就把这个提交方式改了,事务提交与session关闭分开。
二、one2many 一对多关系映射
2.1单向
classes类
public class Classes implements Serializable{
	private Long cid;
	private String name;
	private Set<Student> students;
}student类
public class Student implements Serializable{
	private Long sid;
	private String name;
}映射文件
<class name="Classes" table="CLASSES"> <id name="cid"> <generator class="native"></generator> </id> <property name="name"></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"> <!-- key:外键,告诉hibernate通过cid来建立classes与student的关系 --> <key column="cid"></key> <one-to-many class="Student"/> </set> </class>
<class name="Student" table="STUDENT"> <id name="sid"> <generator class="native"></generator> </id> <property name="name"></property> </class>测试类,主要看hibernate发出的sql语句
public class One2manyTest {
	private Session session;
	private Transaction transaction;
	
	@Before
	public void init(){
		session = HibernateUtils.openSession();
		transaction = session.beginTransaction();
	}
	/**
	 * 一对多的单向操作
	 */
	@Test
	public void testSaveClass_cascade_SaveStudent(){
		Classes classes = new Classes();
		classes.setName("软件");
		Set<Student> students = new HashSet<Student>();
		Student student = new Student();
		student.setName("A");
		students.add(student);
		classes.setStudents(students);
		session.save(classes);//需要设置cascade
	}
	
	/**
	 * sessin.flush的时候
	 *    1、检查一级缓存中所有的持久化状态的对象
	 *        判断发出insert语句或者update语句
	 *    2、检查所有的持久化对象的关联对象
	 *         如果关联对象是由临时状态转化过来的,则对关联对象发出insert语句
	 *         如果关联对象是从数据库中提取出来的,则对照副本,决定是否发出update语句
	 */
	@Test
	public void testUpdateClass_cascade_UpdateStudent(){
		Classes classes = (Classes) session.get(Classes.class, 3L);
		Set<Student> students = classes.getStudents();
		for(Student student : students){
			student.setName("AA");
		}
		session.update(classes);
	}
	
	/**
	 * 维护关联关系
	 * 更新班级  级联  保存学生
	 */
	@Test
	public void testUpdateClass_cascade_SaveStudent(){
		Classes classes = (Classes)session.get(Classes.class, 3L);
		
		Student student = new Student();
		student.setName("cc");
		//建立班级与学生之间的关系
		classes.getStudents().add(student);
		
		
		//看发出sql语句
		/**
		 * Hibernate: 
		    update
		        STUDENT 
		    set
		        cid=? 
		    where
		        sid=?
		    维护关联关系:inverse:false由本身维护,true由对方维护,默认false
		    inverse设置为true,有Student维护关联关系,就不发送最后的update语句
		 */
	}
	@After
	public void destory(){
		transaction.commit();
		session.close();
	}
}2.2双向public class Student implements Serializable{
	private Long sid;
	private String name;
	private Classes classes;
	}
<class name="Student" table="STUDENT"> <id name="sid"> <generator class="native"></generator> </id> <property name="name"></property> <!-- name:Student类属性 column:外键 --> <many-to-one cascade="save-update" name="classes" column="cid" class="Classes"> </many-to-one> </class>
测试类
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();
	}
}inverse与cascade的关系
cascade指的是级联操作,操作的是一般属性,指的是对象与对象的操作
inverse指的是关系操作,针对的是外键
一对的多的双向:当多的一方维护关系时,不会发出更新关系的update语句,而一的一方维护关关系时需要发出维护关系的update语句,一般情况下,多的一方维护关系效率比较高。
版权声明:本文为博主原创文章,未经博主允许不得转载。
Hibernate学习笔记(四) — session的产生方式 与 一对多关系映射
原文:http://blog.csdn.net/wjw0130/article/details/47379385