JavaEE学习笔记——Hibernate篇

文章部分内容整理自郭永锋视频教学内容!   

目录

1、get和load方法的区别

2、查询对象 

3、主键的生成策略

4、Hibernate 实体的状态以及状态之间的在转换

5、一级缓存 

6、快照

7、Hibernate的多表关联关系映射(一)(例:客户订单之间的关系为一对多、多对一)

8、cascade级联

9、Hibernate的多表关联关系映射(二)(例:学生、课程之间的关系为多对多)

10、悲观锁 【分为读锁(共享锁)和写锁(排它锁)】

11、乐观锁

12、悲观锁和乐观锁的比较

13、二级缓存

 


 

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章