文章部分内容整理自郭永锋视频教学内容!
目录
7、Hibernate的多表关联关系映射(一)(例:客户订单之间的关系为一对多、多对一)
9、Hibernate的多表关联关系映射(二)(例:学生、课程之间的关系为多对多)
1、get和load方法的区别
- get方法是直接加载数据库,返回一个对象
- load的设计是懒加载,事先并不查询数据库,返回的是对象的一个代理,只有用到了对象的相关属性才会去查询数据库
红圈中的标记说明返回的不是一个User对象,而是一个代理 |
load执行原理图 |
2、查询对象
HQL:Hibernate Query Language的缩写,就是Hibernate的查询语言,面向对象查询语言,最终底层要转成面向数据库查询语言。
SQL:直接面向数据库查询语言。
- Query 查询对象:用于查询的对象,可以设置查询条件和分页查询。可使用HQL、SQL语句查询。
-
Criteria查询对象:hibernate提供纯面向对象查询语言,提供直接使用PO对象进行操作。
-
SQLQuery查询对象:使用原生的SQL语句查询
3、主键的生成策略
<id name="uid" column="id">
<!-- generator:id的生成策略
increment:也会自动增长id,但是它的这种增长是自己Hibernate实现
执行select max(id) 查询,这种会有线程并发问题
sequence:一般在oracle数据库才用
hilo:hibernate自己实现的id规则【不用】
native:【常用】
如果是mysql数据库,id会自动增长
如果是oracle数据库,会自动增长,sequence
uuid:【常用】一个长字符串,需要把模型的id改成字符串
保存的时候,不用自己设置ID,hibernate会设置id
assigned:【常用】要手动设置id属性
-->
<generator class="native"></generator>
</id>
4、Hibernate 实体的状态以及状态之间的在转换
- 瞬时状态:session没有缓存,数据库也没有记录,oid没有值
- 持久状态:session有缓存,数据库也有记录,oid有值
- 脱管状态/游离状态:session没有缓存,数据库有记录,oid有值
瞬时状态→持久状态:执行save、update、saveOrUpdate
持久状态→脱管状态:session.close ()、session.clear()、session.evict(obj)5
5、一级缓存
一级缓存:又称为session级别的缓存。当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。当session关闭时,一级缓存销毁。
证明一级缓存。第二次执行session.get()方法将会从session中取值,不会有SQL执行。判断u1==u2结果为true |
当移除缓存后,第二次执行session.get()又会有SQL执行。将会有两次select语句输出 |
6、快照
快照作用:与一级缓存存放位置一样,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。
快照原理:在执行commit提交时,一级缓存将与快照进行对比,如果一级缓存修改了,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。若一级缓存无变化,则不会执行update语句。
快照演示(一级缓存刷新) :session.flush()手动刷新,保持一级缓存与数据库一致,此时会执行两条update语句,如果去除flush代码,只会产生一条update语句。
注意:HQL的结果会进行一级缓存,SQL的结果不会添加到一级缓存
7、Hibernate的多表关联关系映射(一)(例:客户订单之间的关系为一对多、多对一)
实体类的编写 |
Customer.hbm.xml |
<hibernate-mapping package="com.gyf.hibernate.domain">
<class name="Customer" table="t_customer"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" length="20"></property>
<!-- 一个客户有多个定单,Hibernate可以双向描述一对多的关系 set中 name写的是实例的属性 --> <set name="orders"> <!-- column指的是Order表中的外键 --> <key column="customer_id"></key> <one-to-many class="Order"/> </set> </class> </hibernate-mapping> |
Order.hbm.xml |
<hibernate-mapping package="com.gyf.hibernate.domain">
<class name="Order" table="t_order"> <id name="id" column="id"> <generator class="native"></generator> </id>
<!-- 定单名称 --> <property name="name"></property>
<!-- 多个定单对应一个客户,Hibernate可以双向描述一对多的关系 set中 name写的是实例的属性 --> <many-to-one name="customer" class="Customer" column="customer_id"></many-to-one> </class> </hibernate-mapping> |
8、cascade级联
- save-update:级联保存,级联修改. 保存A(客户)时,同时保存B(订单)。
-
delete:级联删除,删除A时,同时删除B。
-
delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。
级联在映射文件的<set>标签中配置 |
级联组合 |
如果需要配置多项,使用逗号分隔。<set cascade="save-update,delete"> all : save-update 和 delete 整合 all-delete-orphan : 三个整合 |
9、Hibernate的多表关联关系映射(二)(例:学生、课程之间的关系为多对多)
实体类的编写 |
Student.hbm.xml |
Course.hbm.xml |
10、悲观锁 【分为读锁(共享锁)和写锁(排它锁)】
- 读锁(共享锁)【用的少】
读锁可被其他线程所共享,如果是读取的话大家都可以用这把锁读到数据。
原理:A线程打开事务并执行select * from table lock in share mode,查出数据,此时A线程拥有了读锁。
接着B线程打开事务并执行select * from table lock in share mode,查出数据,此时读锁转移到了B线程。
这时A执行update语句,会发现A进程停住不动了,update语句处于等待执行状态。
这时因为读锁在B进程身上,当B进程提交事务后,会发现A进程的update语句执行成功。
- 写锁(排它锁)【用的多】
写锁不能共享,只要有人为数据加入了写锁,其他人就不能为数据加任何锁(可以锁一张表,或者锁一行记录)
原理:A线程打开事务并执行select * from table for update,查出数据,此时A线程拥有了写锁。
接着B线程打开事务并执行select * from table for update,发现查不出数据,因为写锁不能共享,此时锁依然在A身上。
当A线程提交事务,B线程将会查出数据并打印。
Hibernate中添加写锁 |
11、乐观锁
乐观锁就是在表中添加一个version字段来控制数据不一致性
在PO对象(javabean)提供字段,表示版本字段。一般为Integer |
在映射文件中配置下Version,该字段由hibernate实现自增 |
原理:假如user表中有一行数据,属性有username和version字段,其中username值为"hd",version值为0
A、B进程同时获取该行数据得到version=0
A修改username字段值为"hh",hibernate实现version字段值的自增,此时version=1
B进程同时也想修改username值为"dd",但发现之前获取到的version=0小于现在version=1,此时B的修改无效并报错
12、悲观锁和乐观锁的比较
悲观锁由数据库实现,乐观锁由hibernate实现。
乐观锁存在的问题:当前台使用的语言和后台hibernate使用的语言不同时,乐观锁将会失效。因为乐观锁由hibernate实现,当前台较先修改完数据后不能让version字段自增,此时后台检测到前后version值一样因此也能成功修改表数据。
13、二级缓存
二级缓存是sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。
二级缓存由类级别缓存区、集合级别缓存区、时间戳缓存区、查询缓存区(又称三级缓存)构成。
(1)适合放入二级缓存中的数据:很少被修改,不是很重要的数据, 允许出现偶尔的并发问题。
(2)不适合放入二级缓存中的数据:经常被修改,如财务数据, 绝对不允许出现并发问题。与其他应用数据共享的数据。
Hibernate中只定义二级缓存接口,实现需要自己选择提供商,通常选择EHCache。