本篇讲到的内容很杂,主要总结了hibernate中的实体创建规则、hibernate主键常见的7种生成策略、hibernate中对象的三种状态:瞬时态,持久化状态和托管/游离态、hibernate的一级缓存的特点和原理以及快照、hibernate事务管理、query查询,criteria查询和原生SQL查询。
、
一、hibernate中的实体规则
1.1、实体类创建的注意事项
(1)持久化类提供无参数构造方法;(2)成员变量私有,提供公有的get、set方法访问,需提供属性;
(3)持久化类中的属性,应尽量使用包装类型,为空时是null,比如考试缺考和考试0分用基本类型无法辨别;
(4)持久化类需要提供oid,与数据库中的主键列对应;
(5)不要用final修饰class(hibernate使用cglib代理生成代理对象,代理对象是继承被代理对象,如果被final修饰,不能被继承,也将无法生成代理)。
1.2、主键类型
hibernate中主键分两种,如下
(1)自然主键(即业务相关主键,在开发中不多见):表的业务列中,有某业务列符合,必须有,并且不重复的特征时,该列可以作为主键使用。
(2)代理主键(即业务无关主键,常用这种):表的业务列中,没有某业务列符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键使用。1.3、主键的生成策略
generator:主键生成策略,就是每条记录录入时,主键生成的策略。class属性有以下常见的7个取值。
(1)identify:主键自增,由数据库维护主键值,录入时不需要指定主键。
(2)sequence:Oracle的主键生成策略。
(3)increment(了解):主键自增,由hibernate来维护主键值,每次插入前会先查询id的最大值,+1作为新主键。
有线程安全问题,多个线程访问时,找最大id会出问题,所以开发时不用!
(4)hilo(了解):主键自增,由hibernate来维护,开发时完全不使用。
(5)native:hilo+sequence+identify 自动三选一策略。
(6)uuid:产生一个永远不重复的随机字符串作为主键,主键类型必须为String类型。
(7)assigned:自然主键生成策略,开发人员手动指定id录入,hibernate不会管理主键值。
hibernate维护主键自增在开发时并没什么用处,每个开发团队会根据需要规定数据库表的主键的生成策略,不需要外界来维护!
二、hibernate中的对象状态
对象分为三种状态:
瞬时状态:没有id,与session没有关联
持久化状态:有id,与session有关联
游离/托管状态:有id,与session没有关联
(上述的id指的是:与数据库对应的id有对应关系,数据库中没有对应的那个id,相当于是没有id)
控制台打印:
学习对象三种状态的结论:将我们希望同步到数据库的数据对应的对象转化为持久化状态!
saveOrUpdate()方法不用考虑对象是瞬时状态还是游离状态,只用直接调这个方法,因为她都会把对象转换为持久化状态,将数据同步到数据库中!
三、hibernate进阶:一级缓存
缓存:预加载,提高效率。hibernate中的一级缓存通过缓存减少对数据库的访问次数,从而提高操作数据库的效率!
3.1、一级缓存特点
(1)只有在session范围内有效,即在session范围内减少对数据库的访问次数,session一旦关闭,一级缓存失效,所以一级缓存作用范围小,缓存的时间短,缓存效果不明显,另外,不同的session不共享缓存数据;
(2)当调用session的save、saveOrUpdate、get、load、list、iterator方法时,都会把对象放入session缓存中;
list查询:一次性把所有的记录都查询出来,会放入缓存,但不会从缓存中取数据;
iterate(N+1次查询):N表示所有的记录总数,即会发送一条语句查询所有的记录的主键,这是第一条查询语句,再根据每一个主键去数据库查询,这是根据第一次查询的条数进行N次查询操作;会放入缓存,也会从缓存中取出数据。
(3)session的缓存是由hibernate维护的,用户不能直接操作缓存内容,只能通过hibernate提供的evict/clear方法操作;
session.flush(); —— 让一级缓存与数据库同步
session.evict(); —— 清空一级缓存中指定的对象
session.clear(); —— 清空一级缓存中的所有对象
3.2、一级缓存提高效率的两个手段
一级缓存提高效率的两个手段分别是
《1》查询时,第一次查询时 ,将对象放入缓存,再次查询这个对象时,会返回缓存中的对象,而不再查询数据库。
《2》修改时,会使用快照对比修改前和修改后对象属性的区别,只执行一次修改。
《1》查询时
例:下面执行了三次get语句查询id为1的对象,但只执行了一次SQL语句。
一级缓存提高查询效率的原理:
《2》修改时(快照)
上面将id为15的名字修改为了“改名”,执行了select和update语句。下面将id为15的名字修改成“改名*2”,再修改为原来的“改名”,控制台执行的SQL语句只有一个select语句,并没有发送update语句,减少了不必要的SQL修改语句的发送!
一级缓存减少不必要SQL语句发送的原理 —— 快照
四、hibernate中的事务
事务:a(原子性)c(一致性)i(隔离性)d(持久性)
事务并发产生的问题:①脏读、②不可重复读、③幻/虚读
事务的隔离级别:1——读未提交(会出现上述问题①②③)、2——读已提交(会出现上述问题②③)、4——可重复读(会出现上述问题③,mysql默认级别)、8——串行化(只允许串行,不允许并发没有问题,效率超低)
一个字节数据来存储隔离级别:0001——1、0010——2、0100——4、1000——8
在hibernate中指定事务隔离级别:
打开hibernate.properties文件(路径如下):
上述在主配置文件(hibernate.cfg.xml)中指定了事务的隔离级别为4。
在真正项目开发当中,事务的隔离级别不是随便就可以定的。
项目中管理事务(指定session与当前线程绑定):
在三层架构中,一般是在Service(业务)层里管理事务的,在业务开始前打开事务,业务执行之后提交事务,执行过程中出现异常,要回滚事务。
在DAO层操作数据库需要用到session对象,在Service层控制事务也是使用session对象完成,我们要确保DAO层和Service层使用的是同一个session对象。(有点类似连接数据库的Connection对象)
在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了,开发人员只需要调用sessionFactory。getCurrentSession()方法即可获得与当前线程绑定的session对象,注意以下两点:
①调用getCurrentSession方法必须配合主配置(hibernate.cfg.xml)中的一段配置:
②通过getCurrentSession方法获得的session对象,当事务提交时,session会自动关闭,不需要我们手动调用close!
五、hibernate中的批量处理
5.1、HQL查询
HQL(hibernate Query Language) hibernate独家查询语言,面向对象的查询语言
基本查询,查询全表:
条件查询,问号占位符:
条件查询,命名占位符:
分页查询:
5.2、criteria查询
hibernate自创的无语句面向对象查询
查询所有:
条件查询:
上面的等于用的是Restrictions.eq(),下面是其他比较运算符的对照表
sql中 | > | >= | < | <= | == | != | in | like | between and | is not null | is null | or | and |
criteria中 | gt | ge | lt | le | eq | ne | in | like | between | is not null | is null | or | and |
分页查询:
查询中总记录数:
控制台打印的SQL语句:
5.3、原生SQL查询
基本查询,查询所有记录:返回数组List
基本查询,将查询结果封装到指定对象中:返回对象List
条件查询:
分页查询:
三种查询比较:
HQL查询:多表查询但不复杂时候使用
Criteria查询:单表查询,(多表时特别烧脑)
原生SQL查询(还是原生用的多):复杂的业务还是用原生SQL