Hibernate学习总结

2018年2月9日10:17:22
  • Hibernate学习总结已关闭评论
  • 211 views
  • A+
所属分类:Hibernate

课程内容

  1. HelloWorld
    1. xml
    2. annotation
  2. Hibernate原理模拟 –什么是O/RMapping以及为什么要有O/RMapping
  3. 常见的O/R框架(了解)
  4. hibernate基础配置(重点)
  5. ID生成策略(重点掌握AUTO)
  6. Hibernate核心开发接口介绍(重点)
  7. 对象的三种状态(了解)
  8. 关系映射(重点)
  9. Hibernate查询(HQL)
  10. 在Struts基础上继续完善BBS2009
  11. 性能优化(重点)
  12. 补充话题

风格

  1. 先脉络,后细节
  2. 先操作,后原理
  3. 重Annotation,轻xml配置文件
    1. JPA
    2. hibernate - extension

资源

  1. http://www.hibernate.org
  2. hibernate zh_CN文档
  3. hibernate annotation references

环境准备

  1. 下载3.2
  2. 下载4.0
  3. 注意阅读hibernate compatibility matrix(hibernate网站,download)
  4. 下载5.8

Hibernate HelloWorld

  1. 建立新的java项目,名为:hibernate_0100_HelloWorld
  2. 学习建立User-library –hibernate,并加入相应的jar包
    1. 项目右键-build path-configure build path-add library
    2. 选择User-library,在其中新建libraray,命名为hibernate
    3. 在该library中加入hibernate所需jar包
      1. hibernate core
      2. /required
  • slf-nop jar
  1. 引入mysql的JDBC驱动包
  2. 在mysql中建立对应的数据库以及表
    1. create database hibernate;
    2. use hibernate;
    3. create table Student (id int primary key, name varchar(20), age int);
  3. 建立hibernate配置文件cfg.xml
    1. 从参考文档中copy
    2. 修改对应的数据库连接
    3. 注释掉暂时用不上的内容
  4. 建立Student类
  5. 建立Student映射文件hbm.xml
    1. 参考文档
  6. 将映射文件加入到cfg.xml中
    1. 参考文档
  7. 写测试类Main,在Main中对Student对象进行直接的存储测试
    1. 参考文档
  8. FAQ:
    1. 要调用new Configuration().configure().buildSessionFactory(),而不是省略configure,否则会出hibernate dialect must be set的异常
  9. Note:
    1. 请务必建立自己动手查文档的能力
    2. 重要的是:
      1. 要建立自己动手查一手文档的信心
      2. 还有建立自己动手查一手文档的习惯!
  • 主动学习,放弃被动接受灌输的习惯!
  1. 建立能力:
    1. 错误读完整
    2. 读出错误的关键行
    3. 排除法
    4. 比较法
    5. google老师

建立Annotation版本的HelloWorld

  1. 创建teacher表,create table teacher (id int primary key, name varhcar(20), title varchar(10));
  2. 创建Teacher类
  3. 在hibernate lib中加入annotation的jar包
    1. hibernate annotaion jar
    2. ejb3 persistence jar
    3. hibernate common annotations jar
    4. 注意文档中没有提到hibernate-common-annotations.jar文件
  4. 参考Annotaion文档建立对应的注解
  5. 在cfg.xml中建立映射<mapping class=…/>
  6. 参考文档进行测试(注意文档中缺少configure()的小bug)
  7. FAQ: @不给提示
    1. content assist –activation – 加上@

What is and Why O/R Mapping

  1. JDBC操作数据库很繁琐
  2. Sql语句编写并不是面向对象的
  3. 可以在对象和关系表之间建立关联来简化编程
  4. O/R Mapping简化编程
  5. O/R Mapping跨越数据库平台
  6. Hibernate_0200_OR_Mapping_Simulation

O/R Mapping Frameworks

  1. hibernate
  2. toplink
  3. jdo
  4. JPA
    1. 意愿统一天下

Hibernate基础配置

  1. 对应项目:Hibernate_0300_BasicConfiguration
  2. 介绍MySQL的图形化客户端
  3. cfg.xml:hbm2ddl.auto
    1. 先建表还是先建实体类
  4. 搭建日志环境并配置显示DDL语句
    1. slf4j与log4j的关系:slf4j像是一个大管家,可以管理许多的日志框架,log4j是其中之一
    2. 加入sl4j-log4j.jar,加入log4j的jar包,去掉slf4j-nop-jar
    3. 从hibernate/project/etc目录copy log4j.properties
    4. 查询hibernate文档,日志部分,调整日志的输出策略
  5. 搭建JUnit环境
    1. 需要注意JUnit的Bug
  6. cfg.xml:show_sql
  7. cfg.xml:format_sql
  8. 表名和类名不同,对表名进行配置
    1. Annotation: @Table
    2. xml:自己查询
  9. 字段名和属性相同
    1. 默认为@Basic
    2. xml中不用写column
  10. 字段名和属性名不同
    1. Annotation: @Column
    2. xml:自己查询
  11. 不需要psersistence的字段
    1. Annotation:@Transient
    2. xml不写
  12. 映射日期与时间类型,指定时间精度
    1. Annotation:@Temporal
    2. xml:指定type
  13. 映射枚举类型
    1. @Enumerated
    2. xml:麻烦
  14. 字段映射的位置(field或者get方法)
    1. best practice:保持field和get set方法的一致
  15. @Lob
  16. 课外:CLOB BLOB类型的数据存取
  17. 课外:Hibernate自定义数据类型
  18. hibernate类型

Hibernate学习总结

ID生成策略

  1. 对应项目:hibernate_0400_ID
  2. 注意:
    1. 我们观察hibernate生成表的结构并不是为了将来就用它生成,(可能还有自己的扩展,比如index等)而是为了明白我们应该建立什么样的表和实体类映射
  3. xml生成id
    1. generator
    2. 常用四个:native identity sequence uuid
  4. @GeneratedValue
    1. 自定义ID
    2. AUTO
      1. 默认:对MySQL,使用auto_increment
      2. 对Oracle使用hibernate_sequence(名称固定)
    3. IDENTITY
    4. SEQUENCE
      1. @SequenceGenerator
    5. TABLE (可以忘记)
      1. @TableGenerator
    6. FAQ:
      1. 用Junit测试时Hibernate SessionFactory 初始化异常不提示。疑似一个bug
      2. 用main来做测试 L
    7. 联合主键
      1. xml: composite-id
        1. 为什么要重写equals和hashCode
        2. 为什么要实现serializable
      2. Annotation
        1. @Embeddable @Id
        2. @EmbeddedID(*)
  • @Id @IdClass(*)

核心开发接口介绍

  1. hibernate_0500_CoreAPI
  2. HibernateAPI文档需要单独下载
  3. Configuration
    1. AnnotationConfiguration
    2. 进行配置信息的管理
    3. 用来产生SessionFactory
    4. 可以在configure方法中指定hibernate配置文件
    5. 只需关注一个方法即:buildSessionFactory()
  4. SessoinFactory
    1. 用来产生和管理Session
    2. 通常情况下每个应用只需要一个SessionFactory
    3. 除非要访问多个数据库的情况
    4. 关注两个方法即:openSession getCurrentSession
      1. opensession每次都是新的,需要close
      2. getCurrentSession从上下文找,如果有,用旧的,如果没有,建新的
        1. 用途,界定事务边界
        2. 事务提交自动close
        3. current-session_context_class (jta thread) (java transaction api)
          1. thread 使用connection
        4. Session
          1. 管理一个数据库的任务单元
          2. 方法(CRUD)
            1. save()
            2. delete
  • load
  1. get
  2. get与load的区别
    1. 不存在对应记录时表现不一样
    2. load返回的是代理对象,等到真正用到对象的内容时才发出sql语句
    3. get直接从数据库加载,不会延迟
  3. update
    1. 用来更新detached对象,更新完成后转为persistent状态
    2. 更新transient对象会报错
    3. 更新自己设定id的transient对象可以(数据库有对应记录)
    4. p状态的对象只要设定不同字段就会发生更新
    5. 更新部分更改的字段
      1. xml 设定property标签的update属性, annotation设定@Column的updatable属性,不过这种方式很少用,因为不灵活
      2. 使用xml中的dynamic-update ,0 Annotation没有对应的属性,hibernate扩展?
        1. 同一个session可以,跨session不行,不过可以用merge() (不重要)
      3. 使用HQL(EJBQL) (建议)
  • saveOrUpdate()
  • clear方法
    1. 无论是load还是get,都会首先查找缓存(一级缓存),如果没有,才会去数据库查找,调用clear()方法可以强制清除session缓存
  1. flush()方法
    1. 可以强制进行从内存到数据库的同步!
    2. FlushMode
  2. find方法已经过时!
  1. SchemaExport
  2. Query接口
    1. 参考Hibernate查询(HQL EJBQL)的内容
  3. Note:
    1. Hibernate中涉及很多非常非常细节的区别,但在实际应用中用得极少,请大家先享受写项目的乐趣,再来探讨这些细节问题
      1. 比如save和persist的区别
      2. merge、evict等方法
  • 比如refresh、lock等
  1. 建议的学习方法,动手实验
  2. 细节问题参考补充视频

三种对象状态

Hibernate学习总结

  1. 上一个project
  2. 三种状态的区分关键在于
    1. 有没有ID,
    2. ID在数据库中有没有
    3. 在内存中有没有(session缓存)
  3. 三种状态:
    1. transient : 内存中一个对象,没ID,缓存中也没有
    2. persistent: 内存中有, 缓存中有, 数据库有(ID)
    3. detached: 内存有, 缓存没有, 数据库有, ID
  4. 对这三种状态需要关注的问题是在该状态下如果进行数据库的操作会发生什么结果,比如改变属性的值会不会发出update语句?
    1. 强烈建议动手实验
    2. 进行正常人的思考
    3. 绝对不要去背这些东西!背过也并不代表你有多牛!

关系映射

对象之间的关系

  1. 这里的关系映射指的是对象之间的关系,并不是指数据库的关系,本章解决的问题是当对象之间处于下列关系之一时,数据库表该如何映射,编程上该如何对待(红色为重点)
  2. 简化问题:
    1. 怎么写Annotation
    2. 增删改查CRUD怎么写
  3. 一对一
    1. 单向(主键、外键)
    2. 双向(主键、外键)
    3. 中间表
  4. 一对多
    1. 单向
    2. 双向
  5. 多对一
    1. 单向
    2. 双向
  6. 多对多
    1. 单向
    2. 双向
  7. 集合映射
    1. List
    2. Set
    3. Map
  8. 继承关系(不重要)
    1. 单表
    2. 多表
    3. 一张主表,多张子表
  9. 组件映射
    1. @Embeddable
    2. @Embedded

一对一关联

  1. 一对一单向外键关联
    1. 项目名称:hibernate_0600_one2one_uni_fk
    2. Annotation: @One2One @JoinColumn
    3. xml: <many-to-one unique
  2. 一对一双向外键关联
    1. 项目名称:hibernate_0700_one2one_bi_fk
    2. Annotation: @One2One(mappedBy)
    3. xml: <many-to-one unique  <one-to-one property-ref
    4. 规律:凡是双向关联,必设mappedBy
  3. 一对一单向主键关联(不重要)
    1. 项目名称:hibernate_0800_one2one_uni_pk
    2. @PrimaryKeyJoinColumn
    3. xml: <one-to-one id使用foreign class
  4. 一对一双向主键关联(不重要)
    1. 项目名称:hibernate_0900_one2one_bi_pk
    2. @PrimaryKeyJoinColumn
    3. xml: <one-to-one id使用foreign class 和 <one-to-one property-ref
  5. 联合主键
    1. 项目名称:hibernate_1000_one2one_uni_fk_composite
    2. @JoinColumns

组件映射

  1. 项目:hibernate_1100_component
  2. 对象关系:一个对象是另外一个对象的一部分
  3. 数据库表:一张表
  4. annotation: @Embbedable @Embbeded
  5. xml: <component

 

 

 

多对一与一对多

  1. 多对一单向关联
    1. 项目名称:hibernate_1200_many2one_uni
    2. 数据库表设计:在多方加外键
      1. 错误做法:在一方加冗余
perosnid personname dreamid
1 zhangsan 1
1 zhangsan 2
dreamid dreamdescr
1 earn money
2 eat a lot
  1. annotaion: @Many2One
  2. xml:<many-to-one
  1. 一对多单向关联
    1. 项目名称:
    2. 类:在一的一方存在多方的集合
    3. 数据库表同上
    4. annotation:@One2Many
    5. xml:<set <one2many
  2. 一对多(多对一)双向关联

 

 

 

 

 

  1. 在车中持有人的引用
  2. hibernate_0900_many2one_1
  3. 结论:不要设置cascade

 

  1. 例如:一个人可以拥有多辆车,人中包含车的列表
  2. hibernate_0800_one2many_1
  3. @One2Many
  4. 默认在集合上的fetch为LAZY

 

多对多

  1. 单向关联:
    1. 项目:hibernate_1500_many2many_uni
    2. 例如:老师和学生的关系,老师需要直到自己教了哪些学生
    3. 数据库:中间表
    4. @Many2Many
    5. <many2many
  2. 双向关联:
    1. 项目:hibernate_1600_many2many_bi
    2. 老师知道自己教了哪些学生,学生也知道教自己的有哪些老师

关联关系中的CRUD_Cascade_Fetch

  1. hibernate_1700_one2many_many2one_bi_crud
  2. 设定cascade可以设定在持久化时对于关联对象的操作(CUD,R归Fetch管)
  3. cascade仅仅是帮我们省了编程的麻烦而已,不要把它的作用看的太大
    1. Cascade的属性指明做什么操作的时候关联对象是绑在一起的
    2. refresh = A 里面需要读B改过之后的数据
  4. 铁律:双向关系在程序中要设定双向关联
  5. 铁律:双向mappedBy
  6. fetch
    1. 铁律:双向不要两边设置Eager(会有多余的查询语句发出)
    2. 对多方设置fetch的时候要谨慎,结合具体应用,一般用Lazy不用eager,特殊情况(多方数量不多的时候可以考虑,提高效率的时候可以考虑)
  7. O/RMapping编程模型
    1. 映射模型
      1. jpa annotation
      2. hibernate  annotation extension
  • hibernate xml
  1. jpa xml
  1. 编程接口
    1. jpa
    2. hibernate
  2. 数据查询语言
    1. HQL
    2. EJBQL(JPQL)
  3. 要想删除或者更新,先做load,除了精确知道ID之外
  4. 如果想消除关联关系,先设定关系为null,再删除对应记录,如果不删记录,该记录就变成垃圾数据
  5. 练习:多对多的CRUD
teacher student
t1 s1
t1 s2
t2 s1
t2 s2

 

关系映射总结

  1. 什么样的关系,设计什么样的表,进行什么样的映射
  2. CRUD,按照自然的理解即可(动手测试)

集合映射(不太重要)

  1. 项目名称:hibernate_1800_Collections_Mapping
  2. Set
  3. List
    1. @OrderBy
  4. Map
    1. @Mapkey

继承映射(不太重要)

  1. 三种方式
    1. 一张总表 SINGLE_TABLE
      1. hibernate_1900_Inheritence_Mapping_Single_Table
    2. 每个类分别一张表 TABLE_PER_CLASS
      1. hibernate_2000_Inheritence_Mapping_Table_Per_Class
    3. 每个子类一张表 JOINED
      1. hibernate_2100_Inheritence_Mapping_JOINED

作业:

  1. 学生、课程、分数的设计(重要)
    1. 使用联合主键@EmbeddedId
      1. 实现Serializable接口
    2. 不使用联合主键
  2. 设计:
    1. 实体类(表)
    2. 导航(编程方便)
    3. 确定了编程方式
  3. 树状结构的设计(至关重要)
    1. 在同一个类中使用One2Many和Many2One

Hibernate查询(Query Language)

HQL vs EJBQL

  1. NativeSQL > HQL > EJBQL(JPQL 1.0) > QBC(Query By Criteria) > QBE(Query By Example)
  2. 总结:QL应该和导航关系结合,共同为查询提供服务。

性能优化

  1. 注意clear()的运用,尤其在不断分页循环的时候
    1. 在一个大集合中进行遍历,遍历msg,取出其中的含有敏感字样的对象
    2. 另外一种形式的内存泄露 //面试题:Java有内存泄漏吗?
  2. 1+ N问题 //典型的面试题
    1. Lazy
    2. BatchSize
    3. join fetch
  3. list 和 iterate不同之处 (//主要为了面试)
    1. list取所有
    2. iterate先取ID,等用到的时候再根据ID来取对象
    3. session 中list第二次发出,仍会到数据库查询
    4. iterate第二次,首先找session级缓存
  4. 一级缓存和二级缓存和查询缓存(面试题)
    1. 什么是缓存
    2. 什么是一级缓存,session级别的缓存
    3. 什么是二级缓存,SessionFactory级别的缓存,可以跨越session存在
      1. 经常被访问
      2. 改动不大不会经常改动
  • 数量有限
  1. 打开二级缓存
    1. cfg.xml设定:
      <property name="cache.use_second_level_cache">true</property>
      <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    2. @Cache注解
  2. load默认使用二级缓存,iterate默认使用二级缓存
  3. list默认往二级缓存加数据,但是查询的时候不使用
  4. 如果要query用二级缓存,需打开查询缓存
    1. <property name="cache.use_query_cache">true</property>
    2. 调用Query的setCachable(true)方法指明使用二级缓存
  5. 缓存算法:(纯为了面试)
    1. LRU、LFU、FIFO
      1. Least Recently Used
      2. Least Frequently Used(命中率高低)
      3. First In First Out
    2. memoryStoreEvictionPolicy="LRU"(ehcache)
  6. 事务并发处理(面试的意义更大)
    1. 事务:ACID
      1. Atomic Consistency Itegrity Durability
    2. 事务并发时可能出现的问题
      1. 第一类丢失更新(Lost Update)
时间 取款事务A 存款事务B
T1 开始事务  
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 汇入100元把余额改为1100元
T6 提交事务
T7 取出100元把余额改为900元
T8 撤销事务
T9 余额恢复为1000 

(丢失更新)

  1. dirty read脏读
时间 取款事务A 转账事务B
T1 开始事务  
T2 开始事务
T3 查询账户余额为1000元
T4 汇入100元把余额改为1100元
T5 查询账户余额为1100元
(读取脏数据)
T6 回滚
T7 取款1100
T8 提交事务失败
  • non-repeatable read不可重复读
时间 取款事务A 转账事务B
T1 开始事务  
T2 开始事务
T3 查询账户余额为1000元
T5 汇入100元把余额改为1100元
T5 提交事务
T6 查询帐户余额为1100元
T8 提交事务
  1. second lost update problem第二类丢失更新 (不可重复读的特殊情况)
时间 转账事务A 取款事务B
T1   开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 取出100元把余额改为900元
T6 提交事务           
T7 汇入100元
T8 提交事务
T9 把余额改为1100 
(丢失更新)
  1. phantom read幻读
时间 查询学生事务A 插入新学生事务B
T1 开始事务  
T2 开始事务
T3 查询学生为10人
T4 插入一个新学生
T5  查询学生为11人
T6 提交事务
T7 提交事务  

 

  1. 数据库的事务隔离机制
    1. 查看sql.Connection文档
    2. 1:read-uncommitted 2: read –committed 4:repeatable read 8: serializable
      1. 0001 0010 0100 1000
      2. C      R   U   D
      3. C | U  0101
      4. 0101 & 0001 == 0001
    3. 只要数据库支持事务,就不可能出现第一类丢失更新
    4. read-uncommitted会出现dirty read, phantom-read,non-repeatable read问题
    5. read-commited 不会出现dirty read,因为只有另一个事务提交才会读出来结果,但仍然会出现non-repeatable read,和phantom-read
    6. repeatable read
    7. serializable解决一切问题
  2. 设定hibernate的事务隔离级别
    1. connection.isolation=2
    2. 用悲观锁解决repeatable read的问题(依赖于数据库的锁)
      1. select …for update
      2. load(xx.class, i, LockMode.Upgrade)
        1. None 无锁的机制,Transaction结束时,切换到此模式
        2. read 在查询的时候hibernate会自动获取锁
        3. write insert update hibernate会自动获取锁
        4. 以上3中锁的模式,是hibernte内部使用的
        5. UPGRADE_NOWAIT ORACLE支持的锁的方式
      3. Hibernate(JPA)乐观锁定(ReadCommitted)
        1. @Version
时间 转账事务A 取款事务B
T1   开始事务
T2 开始事务
T3 查询账户余额为1000元 version = 0
T4 查询账户余额为1000元 version = 0
T5 取出100元把余额改为900元 version = 1
T6 提交事务           
T7 汇入100元
T8 提交事务 ? version > 0

throw exception

T9 把余额改为1100 
(丢失更新)

 

 

 

avatar