hibernate

1 概念

1.1 分层好处

1.2 模型

  • 模型:描述现实实物,面向对象的思想。
  • 域模型:java中的实体类
  • 数据模型:数据库中的表
  • 数据模型之间的关系: 1对n n对n 1对1
  • 域模型之间的关系: 关联 依赖 聚集 一般化
public class Person extends  Animal{//继承::一般化关
系Father father;//每个person都有一个自己的father: 但两者可以是独立
的个体:关联关系

1.3 jdbc缺点

1.4 ORM

orm:object-relational-mapping,对象关系映射,持久层框架的设计原理。java中实体类的属性与关系型数据库表的字段创建一一对应关系。
目的:在进行crud时便于结果集的解析,和占位符的赋值。
1.5 关系模型和域模型的分歧

详细说以下粒度:

2 初次体验

2.1 框架的搭建和使用

1 导入pom依赖

    <dependencies><!--核心包--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.4.20.Final</version></dependency><!--日志相关包--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.30</version></dependency><!--自动生成字节码文件--><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.24.0-GA</version></dependency><!--sql编译--><dependency><groupId>antlr</groupId><artifactId>antlr</artifactId><version>2.7.7</version></dependency><!--commons工具--><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.2</version></dependency><!--事务--><dependency><groupId>javax.transaction</groupId><artifactId>jta</artifactId><version>1.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.37</version></dependency></dependencies>

2 创建表以及实体类

3 创建hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 下面是三个必须要有的配置:配置连接信息,hibernate的方言,银蛇文件的路径 --><!-- 配置连接MySQL数据库的基本参数 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql:///java26</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">19971001</property><!-- 配置Hibernate的方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 下面两个是可选的配置哟! --><!-- 打印sql语句 --><property name="hibernate.show_sql">true</property><!-- 格式化sql语句 --><property name="hibernate.format_sql">true</property><!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --><mapping resource="mapper/Student.hbm.xml"/></session-factory>
</hibernate-configuration>

4 创建hbm映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!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.zhiyou100.entity.Student" table="student"><id name="sid" column="sid"><generator class="native" /></id><property name="sname" column="sname" /><property name="sage" column="sage" /></class>
</hibernate-mapping>

5 创建测试文件

demo01:

import org.hibernate.HibernateException;
import org.hibernate.Metamodel;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;import javax.persistence.metamodel.EntityType;import java.util.Map;/*** @author : code1997* @date :2020-09-2020/9/15 14:59*/
public class Main {private static final SessionFactory ourSessionFactory;static {try {Configuration configuration = new Configuration();configuration.configure();ourSessionFactory = configuration.buildSessionFactory();} catch (Throwable ex) {throw new ExceptionInInitializerError(ex);}}public static Session getSession() throws HibernateException {return ourSessionFactory.openSession();}public static void main(final String[] args) throws Exception {final Session session = getSession();try {System.out.println("querying all the managed entities...");final Metamodel metamodel = session.getSessionFactory().getMetamodel();for (EntityType<?> entityType : metamodel.getEntities()) {final String entityName = entityType.getName();final Query query = session.createQuery("from " + entityName);System.out.println("executing: " + query.getQueryString());for (Object o : query.list()) {System.out.println("  " + o);}}} finally {session.close();}}
}

demo02:

import com.zhiyou100.entity.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;/*** @author : code1997* @date :2020-09-2020/9/15 15:16*/
public class Demo01 {public static void main(String[] args) {//1. 加载Hibernate的核心配置文件Configuration configuration = new Configuration().configure();//如果在Hibernate的核心配置文件没有设置加载哪个映射文件,则可手动加载映射文件//configuration.addResource("com/meimeixia/hibernate/demo01/Customer.hbm.xml");//2. 创建SessionFactory对象,类似于JDBC中的连接池System.out.println("=="+configuration);SessionFactory sessionFactory = configuration.buildSessionFactory();//3. 通过SessionFactory获取到Session对象,类似于JDBC中的ConnectionSession session = sessionFactory.openSession();//4. 手动开启事务,(最好是手动开启事务)Transaction transaction = session.beginTransaction();//5. 编写代码Student student = new Student(1001,"张久",18);session.save(student);//保存一个用户//6. 事务提交transaction.commit();//7. 释放资源session.close();sessionFactory.close();}
}

2.2 CRUD体验

package com.zhiyou100.dao;import com.zhiyou100.entity.Student;
import com.zhiyou100.util.SessionUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;import java.util.List;/*** @author : code1997* @date :2020-09-2020/9/15 17:28*/
public class StudentDao {@Testpublic void addOne(){Session session = SessionUtil.getSession();Transaction transaction = session.beginTransaction();try{Student student = new Student(1,"天球",18);session.save(student);transaction.commit();}catch (Exception exception){transaction.rollback();System.out.println("exception:"+ exception.getMessage());}finally {session.close();}}@Testpublic void deleteOne(){Session session = SessionUtil.getSession();Transaction transaction = session.beginTransaction();try{Student deleteStudent = session.get(Student.class, 10);if (deleteStudent!=null){System.out.println("删除成功");session.delete(deleteStudent);}else {System.out.println("用户不存在,删除失败");}transaction.commit();}catch (Exception exception){transaction.rollback();System.out.println("exception:"+ exception.getMessage());}finally {session.close();}}@Testpublic void getOne(){Session session = SessionUtil.getSession();try{Student student = session.get(Student.class, 9);System.out.println(student);}catch (Exception exception){System.out.println("exception:"+ exception.getMessage());}finally {session.close();}}@Testpublic void queryAll(){Session session = SessionUtil.getSession();try{Query query = session.createQuery("from Student");List<Student> list = query.list();for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}list.forEach(System.out::println);}catch (Exception exception){System.out.println("exception:"+ exception.getMessage());}finally {session.close();}}}

2.3 细节

1 get和load的方法的区别

  • 查询结果不存在的处理方式:

    • get:当查询的结果不存在的时候会返回null。
    • load:当查询结果不存在的时候报错。ObjectNotFoundException。
  • 查询时机不同:
    • get被调用则立即回进行数据库查询。
    • load被调用会返回一个目标对象的代理对象,在这个代理对象中只存储了目标对象的ID值,只有当调用除ID值以外的属性值的时候才会发出SQL查询的。

  • 都会使用缓存:get()和load()都会使用缓存,都是首先从一级缓存Session中查找,当找不到的时候再去二级缓存中查找,当查询不到的时候get()返回的是null,而load()则返回代理对象,如果缓存中存在,两者返回同一个对象。

2 session.createQuery(“from Student”):from后的表名。

  • select from后跟的不是表名,是Entity类名。

    • 如果为Entitiy对象设置了name为“NetPool”,则Entitty对象名就是name后的名字;
    • 如果没有设置name,默认使用public class后的查询类的类名。
  • where后的对象别名 . 属性名,这里的属性名不是@Cloumn(name="")的name的名字。而是当前Entity对象的属性

3 saveOrUpdate的使用

    @Testpublic void saveOrUpdate(){Session session = SessionUtil.getSession();Transaction transaction = session.beginTransaction();try{Student student = new Student(10,"李四",18);session.saveOrUpdate(student);Query query = session.createQuery("from Student");List<Student> list = query.list();list.forEach(System.out::println);transaction.commit();}catch (Exception exception){transaction.rollback();System.out.println("exception:"+ exception.getMessage());}finally {session.close();}}

此方法需要要求改表的主键生成策略不能是自动生成,即去掉:,否则会抛出如下

异常:exception:Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

4 自动创建表

<!--自动进行ddl
1)hibernate.hbm2ddl.auto=create:项目启动创建表: 如果存在 先删除再创建
2)hibernate.hbm2ddl.auto=create-drop: 项目启动创建表: 项目关闭删除表
3)hibernate.hbm2ddl.auto=update: 如果没用就创建 如果有 表结构相同就使用 不同就添加列
4)hibernate.hbm2ddl.auto=validate: 表不存在/不满足映射需求报错  :ExceptionInInitializerError 能满足直接使用-->
<property name="hibernate.hbm2ddl.auto">validate</property>

3 HQL

3.1 查询所有

@Test
public void queryAll(){Session session = SessionUtil.getSession();try{//需要些hql:面向对象Query query = session.createQuery("from com.zhiyou100.entity.Student s");List<Student> list = query.list();list.forEach(System.out::println);}catch (Exception exception){System.out.println("exception:"+ exception.getMessage());}finally {session.close();}
}
@Test
public void queryAll2(){Session session = SessionUtil.getSession();try{//非hsql语句Criteria fromStudent = session.createCriteria(Student.class);List list = fromStudent.list();list.forEach(System.out::println);}catch (Exception exception){System.out.println("exception:"+ exception.getMessage());}finally {session.close();}
}
@Test
public void queryAll3(){Session session = SessionUtil.getSession();try{//使用本地sql的方式,封装的不是对象,是Object[],装了所有的属性,一条记录是一个数组NativeQuery sqlQuery = session.createSQLQuery("select * from student");List<Object[]> list =  sqlQuery.list();for (int i = 0; i < list.size(); i++) {for (int j = 0; j < list.get(i).length; j++) {System.out.println(list.get(i)[j]);}}}catch (Exception exception){System.out.println("exception:"+ exception.getMessage());}finally {session.close();}
}

3.2 条件查询

1 普通查询

@Test
public void test04(){//1、字符串的拼接Query query = session.createQuery("from Student where sage>"+18);List list = query.list();list.forEach(System.out::println);//1、字符串的拼接Query query2 = session.createQuery("from Student where sage>(:ageValue)");query2.setParameter("ageValue", 18);List list2 = query.list();list2.forEach(System.out::println);
}

2 模糊查询

@Test
public void test03(){//支持模糊查询Query query = session.createQuery("from Student where sname like '%赵%'");List list = query.list();list.forEach(System.out::println);
}

3 聚合函数

@Test
public void test01(){//聚合函数的使用,例如:查询存在多少条记录Query query = session.createQuery("select count(*) from Student");Object singleResult = query.getSingleResult();System.out.println(singleResult);Query query2 = session.createQuery("select max(sage) from Student");Object singleResult2= query2.getSingleResult();System.out.println(singleResult2);
}

3.3 结果封装

1 查询某些列

@Test
public void test05(){//1.查询某些列并封装成对象Query query = session.createQuery("select new Student(sname,sage) from Student");List list = query.list();list.forEach(System.out::println);//2.查询多列被封装为Object数组,单列被封装为ObjectQuery query2 = session.createQuery("select sname,sage from Student");List<Object[]> list2 = query2.list();for (int i = 0; i < list2.size(); i++) {for (int j = 0; j < list2.get(i).length; j++) {System.out.println(list2.get(i)[j]);}}list2.forEach(System.out::println);
}

3.4 dml操作

@Test
public void test06(){//进行dml操作Query query = session.createQuery("update Student set sage=sage+1 where sage>="+18);int hang = query.executeUpdate();System.out.println("影响了:"+hang+"行");Query query1 = session.createQuery("from Student where sage>=" + 18);query1.list().forEach(System.out::println);
}

4 Criteria

​ QBC,QueryByCriteria,标准查询。Hibernate Session 接口提供了 createCriteria() 方法,可用于创建一个 Criteria 对象,使当应用程序执行一个标准查询时返回一个持久化对象的类的实例。

4.1 标准查询

由多个类组成:

  • Restrictions:比较运算符相关
  • Order:排序相关
  • Projections:聚合相关

4.2 比较运算符

=   Restrictions.eq() 等于
<>   Restrictions.not(Exprission.eq()) 不等于
>   Restrictions.gt() 大于
>=   Restrictions.ge() 大于等于
<   Restrictions.lt() 小于
<=   Restrictions.le() 小于等于
is null   Restrictions.isnull() 等于空值
is not null   Restrictions.isNotNull() 非空值
like   Restrictions.like() 字符串模式匹配
and   Restrictions.and() 逻辑与
and   Restrictions.conjunction() 逻辑与
or   Restrictions.or() 逻辑或
or   Restrictions.disjunction() 逻辑或
not   Restrictions.not() 逻辑非
in(列表)   Restrictions.in() 等于列表中的某一个值
ont in(列表)   Restrictions.not(Restrictions.in())不等于列表中任意一个值
between x and y   Restrictions.between() 闭区间xy中的任意值
not between x and y   Restrictions.not(Restrictions..between()) 小于值X或者大于值y

简单使用:

@Test
public void test2(){//比较运算Criteria criteria = session.createCriteria(Student.class);criteria.add(Restrictions.gt("sage", 18)).add(Restrictions.like("sname", "%赵%"));List list = criteria.list();list.forEach(System.out::println);
}

4.3 分页使用

方法 方法描述
public Criteria setFirstResult(int firstResult) 这种方法需要一个代表你的结果集的第一行的整数,以第 0 行开始。
public Criteria setMaxResults(int maxResults) 这个方法设置了 Hibernate 检索对象的 maxResults

简单测试:

@Test
public void test3(){//分页查询Criteria criteria = session.createCriteria(Student.class);criteria.setFirstResult(2);criteria.setMaxResults(2);List list = criteria.list();list.forEach(System.out::println);
}

4.4 排序

@Test
public void test4(){//排序Criteria criteria = session.createCriteria(Student.class);criteria.addOrder(Order.desc("sage")).addOrder(Order.asc("sid"));List list = criteria.list();list.forEach(System.out::println);
}

4.5 聚合

@Test
public void test5(){//聚合函数Criteria criteria = session.createCriteria(Student.class);criteria.setProjection(Projections.count("sname"));Object o = criteria.uniqueResult();System.out.println(o);criteria=session.createCriteria(Student.class);criteria.setProjection(Projections.max("sage"));o = criteria.uniqueResult();System.out.println(o);
}

4.6 关联

​ 你可以使用createCriteria()非常容易的在互相关联的实体间建立约束。

List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.createCriteria("kittens")
.add( Restrictions.like("name", "F%")
.list();

参考文档:https://www.cnblogs.com/lukelook/p/9692429.html

5 主键生成策略

​ hibernate要求实体类必须有一个值唯一的属性作为主键id 必须设置主键生成策略。如下

<!--每个class必须指定一个id:主键列:唯一标识-->
<id name="tid" column="t_id"  type="java.lang.Integer"><generator class="assigned"/>
</id>
<id name="tid" column="t_id"  type="java.lang.Integer"><generator class="sequence"><param name="sequence">sequenceName</param></generator>
</id>
  • uuid: 只针对于字符串类型的主键 自动生成32位的16进制字符串

  • increment:只用于int类型的主键 hibernate自增

  • identity:只用于int类型的主键 只使用支持auto_increment的数据库 数据库自增

  • sequence:只用于int类型的主键 只使用支持sequence的数据库 :oracle

  • native: hibernate根据数据库底层来选择

  • assigned: 客户手动输入(默认)

6 检索对象的方式

6.1 对象导航图检索方式

​ 表关联时: student.teacher.father

6.2 OID 检索方式

​ 通过get和load方法由主键id获取对象

6.3 hql检索方式

​ 通过query接口调用hql语句,获取对象

6.4 QBC 检索方式

​ 通过criteria接口获取对象

6.5 本地sql检索方式

​ 通过sqlquery接口,通过sql语句获取对象。

//1  对象导航图检索方式::表关联
//2  OID检索方式:通过get/load方法由id获取对象
Teacher tea=(Teacher)session.get(Teacher.class,1021);
//3  HQL检索方式:通过query接口由hql获取对象
tea=(Teacher)session.createQuery("from com.zhiyou100.entity.Teacher where tid=1031").uniqueResult();
//4 QBC检索方式:通过criteria接口获取对象
tea=(Teacher)session.createCriteria(Teacher.class).add(Restrictions.eq("tid",1041)).uniqueResult();
//5 本地sql检索方式:
SQLQuery  sq=session.createSQLQuery("select * from tab_teacher where t_id=1051");
Object obj=sq.uniqueResult();//获取的是::object[]
sq=session.createSQLQuery("update tab_teacher set t_age=t_age+1");
System.out.println("修改行数:"+sqlQuery.executeUpdate());

7 表之间的关联

7.1 一对多,多对一

7.1.1 环境搭建

1 创建表

drop table school;
create table school(sc_id int primary key AUTO_INCREMENT,sc_name  varchar(20),sc_address varchar(100)
);
commit;
insert into school values(1,'外国语','中原区.桐柏路');
insert into school values(2,'郑州一种','中原区.嵩山路');
drop table teacher;
create table teacher(t_id int primary key Auto_Increment,t_name varchar(30),t_sex varchar(3),sc_id int,CONSTRAINT sc_t_fk foreign key(sc_id) references school(sc_id)
);
commit;
insert into teacher values (1,'韩非子','男',1),(2,'韩寒','男',2),(3,'韩雪','女',1),(4,'韩红','女',2);
select * from teacher;
select * from school;

2 创建实体类

public class School implements Serializable {private Integer scId;private String scName;private String scAddress;private Set<Teacher> teachers;//省略了getAndSet方法以及构造器@Overridepublic String toString() {return "School{" +"scId=" + scId +", scName='" + scName + '\'' +", scAddress='" + scAddress + '\'' +", teachers=" + teachers +'}';}
}
public class Teacher implements Serializable {private Integer tId;private String tName;private String tSex;private School school;@Overridepublic String toString() {return "Teacher{" +"tId=" + tId +", tName='" + tName + '\'' +", tSex='" + tSex + '\'' +'}';}
}

1.限于篇幅,省略了getter,setter。

2.注意toString方法,不能两者循环调用,否则会出现问题,比如栈溢出。

3 导入pom依赖文件

    <build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build><dependencies><!--核心包--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.4.20.Final</version></dependency><!--日志相关包--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.30</version></dependency><!--自动生成字节码文件--><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.24.0-GA</version></dependency><!--sql编译--><dependency><groupId>antlr</groupId><artifactId>antlr</artifactId><version>2.7.7</version></dependency><!--commons工具--><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.2</version></dependency><!--事务--><dependency><groupId>javax.transaction</groupId><artifactId>jta</artifactId><version>1.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.37</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency></dependencies>

4 写映射文件School.hbm.xml和Teacher.hbm.xml

School.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!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.zhiyou100.entity.School" table="school"><id name="scId" column="sc_id"><generator class="identity" /></id><property name="scName" column="sc_name" /><property name="scAddress" column="sc_address" /><!--cascade:级联保存,级联删除--><set name="teachers" cascade="save-update,delete"><!--外键列名字--><key column="sc_id" /><one-to-many class="com.zhiyou100.entity.Teacher" /></set></class>
</hibernate-mapping>

Teacher.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!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.zhiyou100.entity.Teacher" table="teacher"><id name="tId" column="t_id"><generator class="identity" /></id><property name="tName" column="t_name" /><property name="tSex" column="t_sex" /><!--从表列中外键列的id--><many-to-one name="school" class="com.zhiyou100.entity.School" column="sc_id"  cascade="save-update"/></class>
</hibernate-mapping>

5 写hibernate.cfg.xml配置文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration><session-factory><!-- 下面是三个必须要有的配置 --><!-- 配置连接MySQL数据库的基本参数 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql:///java26</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">19971001</property><!-- 配置Hibernate的方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 下面两个是可选的配置哟! --><!-- 打印sql语句 --><property name="hibernate.show_sql">true</property><!-- 格式化sql语句 --><property name="hibernate.format_sql">true</property><!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --><mapping resource="mapper/School.hbm.xml" /><mapping resource="mapper/Teacher.hbm.xml" /></session-factory>
</hibernate-configuration>

6 写个工具类加载配置文件:

public class SessionUtil {private static final SessionFactory ourSessionFactory;static {try {Configuration configuration = new Configuration();configuration.configure();ourSessionFactory = configuration.buildSessionFactory();} catch (Throwable ex) {throw new ExceptionInInitializerError(ex);}}public static Session getSession() throws HibernateException {return ourSessionFactory.openSession();}
}

7 写测试类:采用单元测试的方式

public class SchoolDao {private Session session=null;private Transaction transaction=null;@Beforepublic void init(){session = SessionUtil.getSession();transaction = session.beginTransaction();}@Afterpublic void destory(){transaction.commit();session.close();}@Testpublic void test1(){Query from_student = session.createQuery("from School");List<School> list = from_student.list();list.forEach(System.out::println);}@Testpublic void test2(){//保存一个学校,且整个学校中存在多个老师,需要在配置文件中声明级联保存:cascade="save-update,delete"School school = new School();school.setScName("郸城一中");school.setScAddress("邯郸城");Teacher teacher = new Teacher();teacher.settName("刘星");teacher.settSex("男");HashSet<Teacher> teachers = new HashSet<>();school.setTeachers(teachers);teachers.add(teacher);teacher.setSchool(school);session.saveOrUpdate(school);}@Testpublic void test3(){//保存一个老师,且这个老师在新创建的学校School school = new School();school.setScName("郸城一中2");school.setScAddress("邯郸城");Teacher teacher = new Teacher();teacher.settName("刘星1");teacher.settSex("男");HashSet<Teacher> teachers = new HashSet<>();school.setTeachers(teachers);teachers.add(teacher);teacher.setSchool(school);session.saveOrUpdate(teacher);}
}

7.2 一对一

1 创建表

create table husband(h_id int primary key auto_increment,h_name varchar(30),constraint h_w_fk foreign key husband(h_id) references wife(w_id)
);alter table husband add constraint h_w_fk foreign key husband(h_id) references wife(w_id);
create table wife(w_id int primary key auto_increment,w_name varchar(30)
);

2 创建实体类

public class Husband implements Serializable {private Integer hId;private String hName;private Wife wife;public Husband() {}public Husband(Integer hId, String hName, Wife wife) {this.hId = hId;this.hName = hName;this.wife = wife;}public class Wife {private Integer wId;private String wName;private Husband husband;public Wife() {}

3 创建表,对象映射关系

Husband.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!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.zhiyou100.entity.Husband" table="husband"><id name="hId" column="h_id"><!--定义妻子是主表,丈夫的主键根据妻子的主键来取值--><generator class="foreign"><!--取决与wife的主键值--><param name="property">wife</param></generator></id><property name="hName" column="h_name" /><!--constrained(约束) (可选) 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响save() 和delete() 在级联执行时的先后顺序(也在schema export tool中被使用)。参考:https://www.cnblogs.com/hihtml5/p/6378339.html?utm_source=itdadao&utm_medium=referral--><one-to-one class="com.zhiyou100.entity.Wife" name="wife" constrained="true" /></class>
</hibernate-mapping>

Wife.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!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.zhiyou100.entity.Wife" table="wife"><id name="wId" column="w_id"><generator class="assigned" /></id><property name="wName" column="w_name" /><one-to-one name="husband" class="com.zhiyou100.entity.Husband" cascade="all" /></class>
</hibernate-mapping>

4 测试

package com.zhiyou100.dao;import com.zhiyou100.entity.Husband;
import com.zhiyou100.entity.Wife;
import com.zhiyou100.util.SessionUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.util.List;/*** @author : code1997* @date :2020-09-2020/9/17 14:45*/
public class HusbandDao {private Session session=null;private Transaction transaction=null;@Beforepublic void init(){session = SessionUtil.getSession();transaction = session.beginTransaction();}@Afterpublic void destory(){transaction.commit();session.close();}@Testpublic void test01(){Query from_husband = session.createQuery("from Husband");List list = from_husband.list();list.forEach(System.out::println);}@Testpublic void test02(){Wife wife = new Wife();wife.setwId(28);wife.setwName("小龙女");Husband husband = new Husband();husband.sethName("张三丰");husband.setWife(wife);wife.setHusband(husband);session.save(wife);}@Testpublic void test03(){//删除主表数据:删除妻子的同时会删除丈夫Wife wife = session.get(Wife.class, 21);session.delete(wife);}@Testpublic void test04(){//删除外键表数据:只会删除丈夫Husband husband = session.get(Husband.class, 1);session.delete(husband);}
}

8 状态转换

​ 在 Hibernate 中,持久化对象是存储在一级缓存当中的,一级缓存指 Session 级别的缓存,它可以根据缓存中的持久化对象的状态改变同步更新数据库。

Hibernate 是持久层的 ORM 框架,专注于数据的持久化工作。在进行数据持久化操作时,持久化对象可能处于不同的状态当中。这些状态可分为三种,分别为瞬时态、持久态和脱管态。下面分别针对这三种状态进行简单介绍。

1)瞬时态(transient)

瞬时态也称为临时态或者自由态,瞬时态的对象是由 new 关键字开辟内存空间的对象,不存在持久化标识 OID(相当于主键值),且未与任何的 Session 实例相关联,在数据库中也没有记录,失去引用后将被 JVM 回收。瞬时对象在内存孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系。

2)持久态(persistent)

持久态的对象存在一个持久化标识 OID,当对象加入到 Session 缓存中时,就与 Session 实例相关联。它在数据库中存在与之对应的记录,每条记录只对应唯一的持久化对象。需要注意的是,持久态对象是在事务还未提交前变成持久态的。

3)脱管态(detached)

脱管态也称离线态或者游离态,当持久化对象与 Session 断开时就变成了脱管态,但是脱管态依然存在持久化标识 OID,只是失去了与当前 Session 的关联。需要注意的是,脱管态对象发生改变时 Hibernate 是不能检测到的。

在 Hibernate 运行时,持久化对象的三种状态是可以通过一系列的方法进行转换的。这三种状态之间的转换关系具体如图 1 所示。

从图 1 中可以看出,当一个对象通过 new 关键字创建后,该对象处于瞬时态;当对瞬时态对象执行 Session 的 save() 或 saveOrUpdate() 方法后,该对象将被放入 Session 的一级缓存中,此时该对象处于持久态。

当对持久态对象执行 evict()、close() 或 clear() 操作后,对象会进入脱管态。

当直接执行 Session 的 get()、load()、find() 或 iterate() 等方法从数据库中查询出对象时,查询到的对象也会处于持久态。

当对数据库中的纪录进行 update()、saveOrUpdate() 以及 lock() 等操作后,此时脱管态的对象就过渡到持久态;由于瞬时态和脱管态的对象不在 session 的管理范围内,所以会在一段时间后被 JVM 回收。

9 缓存

9.1 一级缓存

​ Hibernate中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份。其中一级缓存是 Hibernate 的内置缓存,在前面的学习中已经使用过。本节将针对 Hibernate 的一级缓存进行详细讲解。

​ 一级缓存其实就是 Session 缓存。Session 缓存是一块内存空间,用于存储与管理 Java 对象。

​ 在使用 Hibernate 查询对象时,首先会使用对象的 OID 值在 Hibernate 的一级缓存中查找,如果找到匹配的对象,则直接将该对象从一级缓存中取出使用;如果没有找到匹配的对象,则会去数据库中查询对应的数据。当从数据库中查询到所需数据时,该数据信息会存储到一级缓存中。由此可知,Hibernate 一级缓存的作用就是减少对数据库的访问次数。

1 Hibernate 的一级缓存具有如下特点。

  • 当应用程序调用 Session 接口的 save()、update()、saveOrUpdate() 时,如果 Session 缓存中没有相应的对象,则 Hibernate 就会自动把从数据库中查询到的相应对象信息加入到一级缓存中。
  • 当调用 Session 接口的 load()、get() 方法,以及 Query 接口的 list()、iterator() 方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询的对象,则再去数据库中查询对应对象,并添加到一级缓存中。
  • 当调用 Session 的 close() 方法时,Session 缓存会被清空。
  • Session 能够在某些情况下,按照缓存中对象的变化,执行相关的 SQL 语句同步更新数据库,这一过程被称为刷出缓存(flush)。

2 在默认情况下,Session 在如下几种情况中会刷出缓存。

  • 当应用程序调用 Transaction 的 commit() 方法时,该方法先刷出缓存(调用 session.flush() 方法),然后再向数据库提交事务(调 用 commit() 方法)。
  • 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先刷出缓存,以保证查询结果能够反映持久化对象的最新状态。
  • 调用 Session 的 flush() 方法。

以 goods 表为例,此时 goods 表中的数据如图 1 所示。

在 GoodsTest 类中添加一个名为 test2() 的方法,使用该方法证明一级缓存的存在,其代码如下所示:

// 证明一级缓存的存在
@Test
public void test2() {Session session = HibernateUtils.getSession(); // 得到session对象session.beginTransaction();// 获取goods1对象时,由于一级缓存中没有数据,所以会发送SQL语句,查询数据库中的内容Goods goods1 = (Goods) session.get(Goods.class, 1);System.out.println(goods1);// 获取goods2对象时,不会发出SQL语句,会从Session缓存中获取数据Goods goods2 = (Goods) session.get(Goods.class, 1);System.out.println(goods2);session.getTransaction().commit();session.close();
}

在上述代码中,第一次执行 get() 方法时,由于一级缓存中不存在 id 为 1 的 Goods 对象,所以 Hibernate 会发出 SQL 语句查询数据库中 id 为 1 的数据。查到后,会将该数据信息保存到一级缓存中。当再次调用 get() 方法获取该对象时,此时将不会发出 SQL 语句,这是因为该对象是在一级缓存中获取的。

为了验证上面的描述,接下来在 7 行设置断点,用 Debug 方式执行 test2() 方法。程序进入断点后,按 F6 键执行 System.out.println(goods1); 语句后,控制台的显示结果如图 2 所示。

图2 输出结果

从图 2 的显示结果中可以看出,执行第一次 get() 方法后,Hibernate 会向数据库中发出一条 SQL 语句,这说明 goods1 对象是从数据库中查询的。程序继续向下执行第二个输出语句时,控制台显示结果如图 3 所示。

图 3 输出结果

从图 3 的显示结果中可以看出,goods2 对象的查询结果被直接输出了,这说明第二次调用 get() 方法获取 goods2 对象时没有查询数据库,而是直接从一级缓存中获取了 goods2 对象。

9.2 二级缓存

使用步骤:

1 导入jar

<!--二级缓存的jar包-->
<dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-ehcache</artifactId><version>5.4.20.Final</version>
</dependency>

2 配置配置文件

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"updateCheck="false"><diskStore path="java.io.tmpdir/Tmp_EhCache" /><defaultCacheeternal="false"maxElementsInMemory="10000"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="1800"timeToLiveSeconds="259200"memoryStoreEvictionPolicy="LRU" /><cache name="cloud_user"eternal="false"maxElementsInMemory="5000"overflowToDisk="false"diskPersistent="false"timeToIdleSeconds="1800"timeToLiveSeconds="1800"memoryStoreEvictionPolicy="LRU" />
</ehcache>

核心配置文件:

<!--注意配置的顺序:property->mapping->[class-cache]--><!--配置二级缓存--><property name ="hibernate.cache.use_second_level_cache">true </property><!--<property name ="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property >--><!--指定使用哪个缓存框架--><!--<property name="hibernate.net.sf.ehcache.configurationResourceName">classpath:ehcache.xml</property>--><property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property><property name="hibernate.cache.use_query_cache">true</property><!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --><mapping resource="mapper/School.hbm.xml" /><mapping resource="mapper/Teacher.hbm.xml" /><mapping resource="mapper/Wife.hbm.xml" /><mapping resource="mapper/Husband.hbm.xml" /><!--对那些类使用二级缓存--><class-cache usage ="read-write" class ="com.zhiyou100.entity.Husband"/>

3 实际的测试

private Session session=null;
private Transaction transaction=null;
@Before
public void init(){session = SessionUtil.getSession();//transaction = session.beginTransaction();
}
@After
public void destory(){//transaction.commit();session.close();
}
@Test
public void test05(){//获取一个Husband husband = session.get(Husband.class, 7);System.out.println(husband);session.close();session = SessionUtil.getSession();Husband husband1 = session.get(Husband.class, 7);System.out.println(husband1);
}

测试结果:

4 query开启二级缓存

默认情况下:get,load,Iterotor会使用到二级缓存,如果想要query使用到二级缓存,需要我们单独进行配置。

xml配置:

<property name="hibernate.cache.use_query_cache">true</property>

测试

    @Testpublic void test06(){//获取一个session.createQuery("from Husband").setCacheable(true).list();System.out.println(session);session.close();session = SessionUtil.getSession();System.out.println(session);session.createQuery("from Husband").setCacheable(true).list();}

结果展示:

10 基于注解形式Hibernate

1 导入依赖

        <!--导入注解版本的依赖--><dependency><groupId>org.hibernate.common</groupId><artifactId>hibernate-commons-annotations</artifactId><version>5.1.0.Final</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>5.4.20.Final</version></dependency>

2 写实体类

package com.zhiyou.entity;
import javax.annotation.Generated;
import javax.persistence.*;/*** @author : code1997* @date :2020-09-2020/9/18 10:54*/
@Entity
@Table(name="worker")
public class Worker {//主键生成策略@GeneratedValue(strategy=GenerationType.IDENTITY)@Id@Column(name="w_id")private Integer wId;@Column(name="w_name")private String wName;@Column(name = "w_salary")private Float wSalary;public Worker() {}public Worker(Integer wId, String wName, Float wSalary) {this.wId = wId;this.wName = wName;this.wSalary = wSalary;}public Integer getwId() {return wId;}public void setwId(Integer wId) {this.wId = wId;}public String getwName() {return wName;}public void setwName(String wName) {this.wName = wName;}public Float getwSalary() {return wSalary;}public void setwSalary(Float wSalary) {this.wSalary = wSalary;}@Overridepublic String toString() {return "Worker{" +"wId=" + wId +", wName='" + wName + '\'' +", wSalary=" + wSalary +'}';}
}

3 写配置文件:hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration><session-factory><!-- 下面是三个必须要有的配置 --><!-- 配置连接MySQL数据库的基本参数 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql:///java26</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">19971001</property><!-- 配置Hibernate的方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 下面两个是可选的配置哟! --><!-- 打印sql语句 --><property name="hibernate.show_sql">true</property><!-- 格式化sql语句 --><property name="hibernate.format_sql">true</property><mapping class="com.zhiyou.entity.Worker" /><!--<mapping package="com.zhiyou.entity" />--></session-factory>
</hibernate-configuration>

4 编写测试

@Test
public void test01(){Worker worker = session.get(Worker.class, 1);System.out.println(worker);
}

c String toString() {
return “Worker{” +
“wId=” + wId +
“, wName=’” + wName + ‘’’ +
“, wSalary=” + wSalary +
‘}’;
}
}


3 写配置文件:hibernate.cfg.xml```xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration><session-factory><!-- 下面是三个必须要有的配置 --><!-- 配置连接MySQL数据库的基本参数 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql:///java26</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">19971001</property><!-- 配置Hibernate的方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 下面两个是可选的配置哟! --><!-- 打印sql语句 --><property name="hibernate.show_sql">true</property><!-- 格式化sql语句 --><property name="hibernate.format_sql">true</property><mapping class="com.zhiyou.entity.Worker" /><!--<mapping package="com.zhiyou.entity" />--></session-factory>
</hibernate-configuration>

4 编写测试

@Test
public void test01(){Worker worker = session.get(Worker.class, 1);System.out.println(worker);
}

14.hibernate的入门相关推荐

  1. [置顶] Hibernate从入门到精通(十)多对多单向关联映射

    上一篇文章Hibernate从入门到精通(九)一对多双向关联映射中我们讲解了一下关于一对多关联映射的相关内容,这次我们继续多对多单向关联映射. 多对多单向关联映射 在讲解多对多单向关联映射之前,首先看 ...

  2. [置顶] Hibernate从入门到精通(十一)多对多双向关联映射

    上次我们在中Hibernate从入门到精通(十)多对多单向关联映射讲解了一下多对多单向关联映射,这次我们讲解一下七种映射中的最后一种多对多双向关联映射. 多对多双向关联映射 按照我们之前的惯例,先看一 ...

  3. Hibernate从入门到精通(十)多对多单向关联映射

    上一篇文章Hibernate从入门到精通(九)一对多双向关联映射中我们讲解了一下关于一对多关联映射的相关内容,这次我们继续多对多单向关联映射. 多对多单向关联映射 在讲解多对多单向关联映射之前,首先看 ...

  4. (转)Hibernate快速入门

    http://blog.csdn.net/yerenyuan_pku/article/details/64209343 Hibernate框架介绍 什么是Hibernate 我们可以从度娘上摘抄这样有 ...

  5. ijkplayer系列14:从入门到进阶问题树梳理

    ijkplayer系列14:从入门到进阶问题树梳理 基础准备 语法基础: C语言以及JNI开发是必备的能力 C语言语法简单复习 https://anacz.blog.csdn.net/article/ ...

  6. hibrnate教程14~Hibernate JPA注解入门

    一.实体类 /*** 客户* @author http://www.yiidian.com*/ @Entity @Table(name = "t_customer") public ...

  7. Hibernate快速入门+简单示例

    很多人说Hbiernate已经没人用了,市面上有太多可供选择的开源工具.诚然市面上有很多新技术,但是作为初学者,还是要踏踏实实从基础做起,而且Hbiernate有自己的应用场景. 上篇博文 我们介绍了 ...

  8. 走进JavaWeb技术世界14:Mybatis入门

    本文转自互联网,如有侵权必定删除. 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java ...

  9. Hibernate-ORM:14.Hibernate中的命名查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客讲述命名查询,所谓命名查询是什么呢? Hibernate中允许我们在xml,实体类,甚至注解的方式来编 ...

  10. python快速入门答案-Python 开发 14 天快速入门

    专栏亮点 零基础学习,循序渐进:专栏将编程语言的学习路线提炼为基础.中级.高级三层,内容由易到难,循序渐进,简练而生动地为读者呈现知识点. 内容全面,提炼要义:从核心概念到高级知识点,包括基本数据结构 ...

最新文章

  1. python输出到语音播放_用Python写一个语音播放软件
  2. js插件---IUpload文件上传插件(包括图片)
  3. redistemplate 设置失效时间_袋式除尘器滤袋失效分析
  4. Python -- Scrapy 命令行工具(command line tools)
  5. Mysql根据日期查询
  6. Python 技术篇-用request库调用莉莉机器人api接口实现与机器人对话实例演示
  7. css选择器 pa,p~a,p+a区别
  8. 设计模式--装饰者(Decorator)模式
  9. SAP CRM WebClient UI的configuration按钮点击之后,发生了什么事情
  10. Github(3)-本地文件管理
  11. 网易博客挂了,转一篇以前的文章过来纪念一下吧。。
  12. Scan chain/SE,SI,SO 带scan的寄存器
  13. 矩阵快速幂 斐波那契数列
  14. 国内云服务商如何排名?国内云主机服务器哪家好?
  15. 2010年6月3日晚18点23分
  16. java实现地图导航功能吗_Java web实现百度地图导航
  17. 文本溢出隐藏显示... 鼠标移动到元素显示全部内容
  18. IntelliJ IDEA 2019从入门到癫狂
  19. php5.5 wamp,wamp环境单独安装(windows下apache2.4、mysql5.5、php5.5的版本)
  20. 给硬件工程师的入门课-硬件开发流程

热门文章

  1. 小米扫地机器人一直提示安装尘盒_小米扫地机器人怎么清理尘盒滤网?
  2. 淘宝定价的方式有什么,如何根据活动来定价
  3. HTML - 调用腾讯 QQ 进行客服在线聊天(PC)
  4. 安卓u盘格式化工具apk_你听说过badusb么,我扔个U盘你敢捡么?(文末附阿里云盘最新邀请码)...
  5. chrome+链接android手机,为什么android手机限制chrome浏览器数据连接还可以上网
  6. Excel2003和Excel2007对下拉选择和下拉级联选择的操作以及java程序的调用
  7. fg-bg Assignment Imbalance problem
  8. pandorabox安装迅雷远程下载插件
  9. 2022年3月17日YYC松鼠短视频v4.2.6更新-增加详细的站点信息统计图表
  10. scrapy--dytt(电影天堂)