一、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),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>