标签:
一、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