将Session与本地线程绑定
//由于session是单线程对象 所以实际中一般会把它与线程绑定
//保证它的单线程性
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
这个需要在hibernate.cfg.xml中配置
<!-- 配置将hibernate与本地session绑定 保证session是单线程对象 -->
<property name="hibernate.current_session_context_class">thread</property>
实体类的三种状态:
1. 临时态:(无id 与session无关)
User user =new User();
user.setName(“aaa”);
user.setPwd(“123”);
session.save(user);
2.托管态(有id 与session无关)
User user =new User();
user.setId(2);
session.delete(user)
3.持久态(有id 与session有关)
User user=session.get(User.class,1);
Hibernate缓存:
验证一级缓存(默认打开):
执行过程:(存的不是对象 而是对象值,再以某个值作为这个存储的索引,以便下次的寻找 比如id然后再组装成一个对象返回)
查询只做了一次 // 5 具体的crud操作
Student stu1=session.get(Student.class, 3);
System.out.println(stu1);
Student stu2 = session.get(Student.class, 3);
System.out.println(stu2);
一级缓存执行过程:
建立一对多 和多对多关系:
都知道数据库中 有一对多和多对多的关系
比如学生对班级 1对多 学生对课程 就是多对多
一共3步骤:
1. 编写实体类
*在1的一方 需要包含多的一方 也就是之间的关联关系
*在多的一方 需要包含另一方Set<>集合也就是之间的聚合关系
2. 配置xx.hbm.xml文件(需要双向配置)
<many-to-onename="cla" column="class_id" class="com.lsy.entity.Class"></many-to-one>
<!--这个many-to-one配置的是它代表与班级之间的 它是多的关系
配置在多的一方
name属性 为Student类中Class的名称
column为表中外键的列名
class 为1的一方的实体类的路径
-->
<setname="stuSet"cascade="save-update">
<keycolumn="class_id">
</key>
<one-to-manyclass="com.lsy.entity.Student"/>
</set>
<!-- 这个set标签配置的是 它与学生之间它是1的关系(记住hibernate里面是双向维护外键不能只单纯只配置一方)
配置cascade属性:后可以少写一部分代码 在做级联保存 添加 这种时可以直接把多的一方 添加少的一方即可
也就是这部分代码:
Studentstu =new Student();
stu.setAge(21);
stu.setName("asdf");
stu.setSex("男");
Classcla=session.get(Class.class, 1);
//cla.getStuSet().add(stu)
stu.setCla(cla);
可以少写注释了的代码 配置后hibernate帮我们封装
key标签配置外键的列名
最后加上一个one-to-many标签 加上多的一方的class
-->
完整配置见之后代码块
学会了一对多的配置后 对于多对多应该看一下就能明白(直接见代码块)
3. 在核心文件中引入最后测试
student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 配置表与实体间的一一对应关系(mapping) -->
<class name="com.lsy.entity.Student" table="t_student">
<!-- 配置主键 -->
<id name="id" column="id">
<!--配置主键生成策略 native表示主键自动增长 -->
<generator class="native"></generator>
</id>
<!-- 配置其他的字段 name 实体类属性名称 column表字段名称 -->
<property name="name" column="name"></property>
<property name="sex" column="sex"></property>
<property name="age" column="age"></property>
<!--配置1对多(多的一方) -->
<many-to-one name="cla" column="class_id" class="com.lsy.entity.Class"></many-to-one>
<!--配置多对多 -->
<set name="courseSet" table="student_course" cascade="save-update,delete">
<key column="stu_id"></key>
<many-to-many column="course_id" class="com.lsy.entity.Course"></many-to-many>
</set>
</class>
</hibernate-mapping>
Student.java
package com.lsy.entity;
import java.util.HashSet;
import java.util.Set;
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
private Class cla;
private Set<Course> courseSet=new HashSet<Course>();
public Set<Course> getCourseSet() {
return courseSet;
}
public void setCourseSet(Set<Course> courseSet) {
this.courseSet = courseSet;
}
public Class getCla() {
return cla;
}
public void setCla(Class cla) {
this.cla = cla;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
class.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.lsy.entity.Class" table="t_class" >
<id name="cid" column="id">
<generator class="native"></generator>
</id>
<!-- 配置其他的字段
name 实体类属性名称
column表字段名称
-->
<property name="name" column="name"></property>
<!-- 这个many-to-one 配置的是它代表与系之间的 它是多的关系-->
<many-to-one name="dep" column="dep_id" class="com.lsy.entity.Department"></many-to-one>
<!-- 配置1对多(多的一方): -->
<set name="stuSet" cascade="save-update,delete">
<key column="class_id">
</key>
<one-to-many class="com.lsy.entity.Student"/>
</set>
</class>
</hibernate-mapping>
Class.java
package com.lsy.entity;
import java.util.HashSet;
import java.util.Set;
public class Class {
private int cid;
private String name;
private Set<Student> stuSet=new HashSet<Student>();
private Department dep;
public Department getDep() {
return dep;
}
public void setDep(Department dep) {
this.dep = dep;
}
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStuSet() {
return stuSet;
}
public void setStuSet(Set<Student> stuSet) {
this.stuSet = stuSet;
}
}
做级联crud的测试代码:
@Test
public void testOneToMany() {
SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.openSession();
Transaction tran;
try {
tran = session.beginTransaction();
Student stu = new Student();//瞬时态对象
stu.setAge(21);
stu.setName("asdf");
stu.setSex("男");
Class cla = session.get(Class.class, 1);
stu.setCla(cla);
session.save(stu);
tran.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
sf.close();// 真正项目中不用关闭
}
}
@Test
public void testOneToManyDelete() {
SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.openSession();
Transaction tran;
try {
tran = session.beginTransaction();
Class cla = session.get(Class.class, 1);
session.delete(cla);
tran.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
sf.close();
}
}
@Test
public void testOneToManyUpdate() {
SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.openSession();
Transaction tran;
try {
tran = session.beginTransaction();
Student stu = session.get(Student.class,1);
stu.setName("Benjamin");
//原本stu的class_id是1 现在想让它是2
Class cla = session.get(Class.class, 2);
cla.getStuSet().add(stu);
stu.setCla(cla);
//session.save(stu); 持久态的对象会自动更新 意思不用save 它也会帮你更新
tran.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
sf.close();// 真正项目中不用关闭
}
}
@Test
public void testManyToMany1() {
SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.openSession();
Transaction tran = session.beginTransaction();
try {
Student stu = session.get(Student.class, 2);// 持久态对象
Course course1 = session.get(Course.class, 1);// 持久态对象
Course course2 = session.get(Course.class, 3);
stu.getCourseSet().add(course1);
stu.getCourseSet().add(course2);
session.save(stu);
tran.commit();
} catch (Exception e) {
e.printStackTrace();
tran.rollback();
} finally {
session.close();
sf.close();// 真正项目中不用关闭
}
}
@Test
public void testManyToMany2() {
SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.openSession();
Transaction tran = session.beginTransaction();
try {
Student stu = new Student();
stu.setId(5);
stu.setName("jack");
stu.setAge(20);
stu.setSex("男");
Course course1 = new Course();
course1.setName("JAVA");
course1.setCredit(4);
Course course2 = new Course();
course1.setName("Python");
course1.setCredit(2);
stu.getCourseSet().add(course1);
stu.getCourseSet().add(course2);
session.save(stu);
tran.commit();
} catch (Exception e) {
e.printStackTrace();
tran.rollback();
} finally {
session.close();
sf.close();// 真正项目中不用关闭
}
}
无论是一对多还是多对多做级联保存时 都需要在set 设置cascade 的值为 “save-update”
执行上面的这个测试方法时testOneToManyUpdate()
做修改时有这问题 (他会修改两次 显然有一次是多余的原因是因为双方都维护了外键)
解决方式:为提高性能 会让其中的一方放弃维护外键,一般让一的那一方, inverse属性 值为:false(默认) 代表不放弃 true代表放弃
<!-- 配置1对多(多的一方): -->
<set name="stuSet" cascade="save-update,delete" inverse="true" >
而一对多做删除时 比如删除班级 然后删除此班级的所有学生 可以在cascade 中设置 delete 多个值之间有,逗号分开 调用方法session.delete();
多对多时不需要调用session.delete 而是调用其中一方的Set集合的remove方法 使用delete时除了将第三张表中两对象的ID删除在原来的表中也会删除。