Hibernate学习
Hibernate基本配置
### 实体类
package com.xiao;
import lombok.Data;
Hibernate核心配置文件
实体类映射文件
测试类
import com.xiao.GoodsEntity;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestGoods {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
/**
* 执行test之前执行的代码
*/
hibernate表关系
一对多
单向关系
实体类
package com.xiao;
import lombok.Data;
import lombok.Data;
映射文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xiao"> <class name="Student" table="Student"> <id name="id"> <generator class="uuid"></generator> </id> <property name="sname" column="sname"></property> <!-- 映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 name: N端对应1端的属性名字 class: 1端对应的类 column: 一那一端在多的一端对应的数据表中的外键的名字 --> <many-to-one name="classess" class="Classess" column="cid"/> </class> </hibernate-mapping>
测试类
import com.xiao.Classess; import com.xiao.GoodsEntity; import com.xiao.Student; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; public class TestGoods { private SessionFactory sessionFactory; private Session session; private Transaction transaction; /** * 执行test之前执行的代码 */ @Before public void init() { Configuration configuration = new Configuration().configure();//创建配置对象 sessionFactory = configuration.buildSessionFactory();//创建session工厂 session = sessionFactory.openSession();//获得session对象 transaction = session.beginTransaction();//打开事务管理 } /** * 执行After之后的的代码 */ @After public void destory() { transaction.commit();//事务提交 session.close();//关闭会话 sessionFactory.close();//关闭会话工厂 } @Test public void testGoods() { //生成对象 GoodsEntity goodsEntity = new GoodsEntity("男朋友", 5633333.3); //保存对象数据库 session.save(goodsEntity); Classess classess = new Classess("软件一班"); Student student1 = new Student("肖杰斌"); Student student2 = new Student("鹿丽娟"); student1.setClassess(classess); student2.setClassess(classess); session.save(classess); session.save(student1); session.save(student2); } }
双向关系
实体类
package com.xiao; import lombok.Data; import java.util.HashSet; import java.util.Set; @Data public class Classess { public Classess() { } public Classess(String name) { this.name = name; } private String id; private String name; /* * 1. 声明集合类型时, 需使用接口类型, 因为 hibernate 在获取 * 集合类型时, 返回的是 Hibernate 内置的集合类型, 而不是 JavaSE 一个标准的集合实现. * 2. 需要把集合进行初始化, 可以防止发生空指针异常 */ private Set<Student> student=new HashSet<>(); }
package com.xiao; import lombok.Data; @Data public class Student { private String id; private String sname; public Student(String sname) { this.sname = sname; } private Classess classess; public Student() { } }
映射文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xiao"> <class name="Classess" table="Classess"> <id name="id" column="cid"> <generator class="uuid"></generator> </id> <property name="name" column="name"></property> <!-- 映射 1 对多的那个集合属性 --> <!-- set: 映射 set 类型的属性, name:一的这一端关联的多的那一端的属性名, table: set 中的元素对应的记录放在哪一个数据表中. 该值需要和多对一的多的那个表的名字一致 --> <set name="student" table="Student"> <!-- 指定关联的表中的外键列的名字 --> <key column="cid"></key> <!-- 指定映射类型 --> <one-to-many class="Student"></one-to-many> </set> </class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xiao"> <class name="Student" table="Student"> <id name="id"> <generator class="uuid"></generator> </id> <property name="sname" column="sname"></property> <!-- 映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 name: N端对应1端的属性名字 class: 1端对应的类 column: 一那一端在多的一端对应的数据表中的外键的名字 --> <many-to-one name="classess" class="Classess" column="cid"/> </class> </hibernate-mapping>
一对多级联
级联的添加
配置
<set name="orders" table="ORDERS" cascade="save-update">
测试
@Test public void testOne() { Classess r1 = new Classess("软件一班"); Student s1 = new Student("小李子"); Student s2 = new Student("李瘦子"); r1.getStu().add(s1); r1.getStu().add(s2); session.save(r1); }
级联删除
<set name="orders" table="ORDERS" cascade="save-update,delete">
@Test public void testTwo(){ Classess classess = session.get(Classess.class, "402880ea6abfcf45016abfcf49ce0000"); session.delete(classess); }
级联修改
<!-- inverse true放弃维护关系 flase维护关系--> <set name="stu" table="T_student" cascade="save-update,delete" inverse="true">
@Test public void update(){ Student student = session.get(Student.class, "402880ea6abfdd92016abfdd97820001"); Classess classess = session.get(Classess.class, "402880ea6abfdd92016abfdd97650000"); student.setClassess(classess); }
多对多
实体类
package com.entity; import lombok.Data; import java.util.HashSet; import java.util.Set; @Data public class StudentTwo { private Integer sid; private String sname; private Set<Course> courseSet=new HashSet<>(); }
package com.entity; import lombok.Data; import java.util.HashSet; import java.util.Set; @Data public class Course { private int cid; private String cname; private Set<StudentTwo> studentSet = new HashSet<>(); }
配置文件
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.entity.StudentTwo" table="student"> <id name="sid" column="sid"> <generator class="increment"/> </id> <property name="sname"/> <!-- 要查询所有course,就需要通过连接表,所以申明连接表的名称 --> <set name="courseSet" table="student_course" cascade="save-update,delete"> <!-- 本实体类在连接表中的外键名称,让hibernate知道连接表或者那个有一个外键为s_id的指向本实体类--> <key column="s_id"></key> <!-- 多对多映射管理,映射类和其映射类在连接表中的外键名名称--> <many-to-many class="com.entity.Course" column="c_id"></many-to-many> </set> </class> <class name="com.entity.Course" table="course"> <id name="cid" column="cid"> <generator class="increment"/> </id> <property name="cname" column="cname"></property> <set name="studentSet" table="student_course" cascade="save-update,delete"> <key column="c_id"></key> <many-to-many column="s_id" class="com.entity.StudentTwo"></many-to-many> </set> </class> </hibernate-mapping>
级联添加数据
/** * 级联添加 */ @Test public void testTree(){ Course course = new Course(); course.setCname("物理"); StudentTwo student = new StudentTwo(); student.setSname("李窝"); student.getCourseSet().add(course); session.save(student); }
级联删除
@Test public void testDelete(){ Course course = session.get(Course.class, 1); session.delete(course); }
维护第三张表的关系
@Test public void testFive(){ Course course = session.get(Course.class, 2); StudentTwo studentTwo = session.get(StudentTwo.class, 3); course.getStudentSet().add(studentTwo); } @Test public void testSix(){ Course course = session.get(Course.class, 2); StudentTwo studentTwo = session.get(StudentTwo.class, 3); course.getStudentSet().remove(studentTwo); }
hibernate查询方式
对象导航查询
应用场景:根据ID查询某个班级,在查询这个班级里的学生
/** * 对象导航查询 */ @Test public void testSelect(){ Classess classess = session.get(Classess.class, "402880ea6ac3ec5e016ac3ec619c0000"); Set<Student> stu = classess.getStu(); System.out.println(stu.size()); }
OID查询
应用场景:根据ID查询某一条记录,返回对象
@Test public void testSelect(){ Classess classess = session.get(Classess.class, "402880ea6ac3ec5e016ac3ec619c0000"); System.out.println(classess); }
HQL查询
Query对象,写HQL语句实现查询
常用的HQL语句 1. 查询所有 from 实体类 2. 条件查询 from 实体类 where 实体类属性 = ?0或者:value 3. 模糊查询 from 实体类 where 实体类属性 like ?0或者:value 4. 排序查询 from 实体类 order by 实体类属性 [asc升序|desc降序] 5. 分页查询 from 实体类 (通过query设置参数,详情看代码) 6. 投影查询 select 实体类属性名称1,书体类属性名称2 from 实体类名称 7. 聚集函数查询 select count(*) from 实体类名称 | count、sum、avg、max、min
1.查询所有
/** * * HQL查询所有数据 */ @Test public void testSelect1(){ Query from_student_ = session.createQuery("from Student"); List<Student> list = from_student_.list(); for (Student student:list){ System.out.println(student); } }
2.条件查询
/** * HQL条件查询 * 在hibernate4.1之后已经对HQL查询参数中的占位符做了改进, * 可以用改命名的方式修改,或者改为JPA占位符的方式。 */ @Test public void testSelect2(){ // Query from_student_ = session.createQuery("from Student where id = ?0"); //from_student_.setParameter(0,"402880ea6ac3ec5e016ac3ec61bc0001"); Query from_student_ = session.createQuery("from Student where id = :id"); from_student_.setParameter("id","402880ea6ac3ec5e016ac3ec61bc0001"); List<Student> list = from_student_.list(); for (Student student:list){ System.out.println(student); } }
3.模糊查询
/** * HQL条件查询 * 模糊查询 */ @Test public void testSelect2(){ Query from_student_ = session.createQuery("from Student where sname like ?0"); from_student_.setParameter(0,"%胖%"); List<Student> list = from_student_.list(); for (Student student:list){ System.out.println(student); } }
4.排序查询
/** * HQL排序查询 */ @Test public void testSelect2(){ Query from_student_ = session.createQuery("from Student order by id desc "); List<Student> list = from_student_.list(); for (Student student:list){ System.out.println(student); } }
5.分页查询
/** * HQL分页查询 */ @Test public void testSelect3(){ Query from_student_ = session.createQuery("from Student"); //设置分页数据 //设置开始位置 from_student_.setFirstResult(0); //设置每页记录数 from_student_.setMaxResults(2); List<Student> list = from_student_.list(); for (Student student:list){ System.out.println(student); } }
6.投影查询
/** * HQL投影查询 */ @Test public void testSelect4(){ Query from_student_ = session.createQuery("select id,sname from Student"); List<Object> list = from_student_.list(); for (Object student:list){ System.out.println(student.toString()); } }
7.聚集函数使用
/** * HQL聚集函数 */ @Test public void testSelect5() { Query from_student_ = session.createQuery("select count(*) from Student"); Object o = from_student_.uniqueResult(); System.out.println(o); }
8.HQL多表查询
1.内连接
SELECT * FROM classess c,t_student s WHERE c.cid=s.cid
@Test public void testSelect13() { Query query = session.createQuery("from Classess c inner join c.stu"); List list = query.list(); }
2.迫切内连接
1. 迫切内连接和内连接底层实现是一样的 2. 区别:使用内连接返回值是一个list集合,迫切内连接返回的是对象
/** * 迫切内连接 */ @Test public void testSelect14() { Query query = session.createQuery("from Classess c inner join fetch c.stu"); List list = query.list(); }
3.左外连接
SELECT * FROM classess c LEFT JOIN t_student s ON c.cid=s.cid
@Test public void testSelect13() { Query query = session.createQuery("from Classess c left join c.stu"); List list = query.list(); }
4.迫切左外连接
迫切左外连接from 实体类 C left join fetch c.字段名
/** * 迫切左外连接 */ @Test public void testSelect14() { Query query = session.createQuery("from Classess c left join fetch c.stu"); List list = query.list(); }
5.右外连接
SELECT * FROM classess c right JOIN t_student s ON c.cid=s.cid
#####
@Test public void testSelect13() { Query query = session.createQuery("from Classess c tight join c.stu"); List list = query.list(); }
QBC查询
1.不需要写SQL语句,调用方法实现 2.操作实体类和属性 3.使用Criteria对象实现
\’注:此对象在5.2版本已经过时\’
#### 1.查询所有
@Test public void testSelect6(){ Criteria criteria = session.createCriteria(Student.class); List<Student> list = criteria.list(); for (Student stu:list ) { System.out.println(stu.getId()+"::"+stu.getSname() ); } }
2.条件查询
@Test public void testSelect7(){ Criteria criteria = session.createCriteria(Student.class); //使用criteria对象里面的方法设置条件值 //首先使用add方法,表示设置条件值 //在add方法里面实用类的方法实现条件设置,类似于cid=:cid criteria.add(Restrictions.eq("id","402880ea6ac3ec5e016ac3ec61bc0001")); List<Student> list = criteria.list(); for (Student stu:list ) { System.out.println(stu.getId()+"::"+stu.getSname() ); } }
3.模糊查询
@Test public void testSelect8(){ Criteria criteria = session.createCriteria(Student.class); //使用criteria对象里面的方法设置条件值 //首先使用add方法,表示设置条件值 //在add方法里面实用类的方法实现条件设置,类似于cid=:cid criteria.add(Restrictions.like("sname","%胖%")); List<Student> list = criteria.list(); for (Student stu:list ) { System.out.println(stu.getId()+"::"+stu.getSname() ); } }
4.排序查询
@Test public void testSelect9() { Criteria criteria = session.createCriteria(Student.class); criteria.addOrder(Order.desc("id")); List<Student> list = criteria.list(); for (Student stu : list ) { System.out.println(stu.getId() + "::" + stu.getSname() ); } }
5.分页查询
@Test public void testSelect10() { Criteria criteria = session.createCriteria(Student.class); //设置分页数据 //设置开始位置,开始位置(当前页-1)* 每页显示数 criteria.setFirstResult(0); //每页显示记录数 criteria.setMaxResults(1); List<Student> list = criteria.list(); for (Student stu : list ) { System.out.println(stu.getId() + "::" + stu.getSname() ); } }
6.统计查询
@Test public void testSelect11() { Criteria criteria = session.createCriteria(Student.class); criteria.setProjection(Projections.rowCount()); Object o= criteria.uniqueResult(); System.out.println(o); }
7.离线查询
@Test public void testSelect12() { //创建对象 DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Student.class); //最终执行时候需要session Criteria executableCriteria = detachedCriteria.getExecutableCriteria(session); List<Student> list = executableCriteria.list(); for (Student stu:list ) { System.out.println(stu.getId() + "::" + stu.getSname()); } }
本地查询
SQLQuery对象,使用普通SQL实现查询
Hibernate检索策略
### Hiberatenate检索分为两类
1.立即查询
1.立即查询:根据ID查询,调用get方法,一调用方法就会立即发送SQL语句进行查询。
/** * 立即查询 */ @Test public void testSelect15(){ //会直接发送SQL语句向数据库获取内容 Student student = session.get(Student.class, "4028b8816ac842f7016ac84321100001"); }
2.延迟查询
2.延迟查询:根据ID查询,还有load方法,调用load方法不会马上发送语句查询数据,只有得到对象里面的值时候才会发送语句查询数据库。 <1>类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送SQL语句 <2>关联级别延迟:查询班级,通过班级查询班级学生,查询班级学生的过程是否需要延迟,这个过程称为关联级别延迟。
/** * 延迟查询 */ @Test public void testSelect15(){ Student student = session.load(Student.class, "4028b8816ac842f7016ac84321100001"); //load返回的是ID,获取ID时,不会发送SQL语句 System.out.println(student.getId()); //调用除ID外其他属性,会发送SQL语句 System.out.println(student.getName()); }
/** * hibernate 级联延迟,默认设置 */ @Test public void testSelect16(){ //通过get获取对象,发送SQL语句 StudentTwo studentTwo = session.get(StudentTwo.class, 1); //不会发送SQL语句 Set<Course> courseSet = studentTwo.getCourseSet(); //获取值发送SQL语句 System.out.println(courseSet.size()); }
3.关联级别延迟操作
1.在映射文件中进行配置实现 <1>根据班级获得班级学生,在班级映射文件中高配置 2.在set标签上使用属性 lazy <1>fetch:值 select <2>lazy:值: -true 延迟 -false 不延迟 -extra 及其延迟
<set name="courseSet" table="student_course" cascade="save-update,delete" fetch="select" lazy="false[true|false|extra]">
批量抓取
场景:查询所有班级,得到CLASSESS的集合,获得所有班级,遍历班级获得所有学生的信息。
/** * 未优化 */ @Test public void testSelect17(){ Query from_classess = session.createQuery("from Classess"); List<Classess> list = from_classess.list(); for (Classess classess:list ) { System.out.println(classess.getId()+"::"+classess.getName()); Set<Student> stu = classess.getStu(); for (Student stud:stu ) { System.out.println(stud.getId()+"::"+stud.getSname()); } } }
batch-size值越大,优化越好。 <set name="courseSet" table="student_course" cascade="save-update,delete" batch-size="2">
版权声明:本文为xiaocore原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。