
苟耀:蜗牛学院高级讲师,11年Java开发和教学经验。专攻Java Web开发,具备全栈开发能力,精通JavaScript、Bootstrap、jQuery、Mybatis、SpringMVC、Spring、Springboot、Mysql等Web开发相关技术,对框架底层原理有深入的理解。授课风趣幽默, 注重逻辑善于从技术原理出发,授之以渔。
Session对象
Session对象是Hibernate中的重要对象,它表示了Hibernate与数据库的会话,是对JDBC Connection的封装,通过该对象我们可以执行增、删、改以及查询单个对象的功能。
Session缓存:一级缓存
在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期,位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应。Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush)。也叫一级缓存。
以下为Session缓存和数据库数据的关系:

以下将讲解Session对象中的重要方法,以及这些方法对Session缓存和数据库记录造成的影响。
flush方法:session会按照缓存中对象属性的变化来更新数据库中的记录,使数据库中记录和缓存中的对象保持一致,但是flush并不会提交事务。值得注意的是当提交事务时会自动执行flush方法更新数据库的记录。
refresh方法:强制发送select语句, 以使数据库中的记录和缓存中的对象保持一致。在同一个事务中如果先查询出数据,然后在数据库中手动的修改了数据并且未提交事务之前,然后执行refresh的方法会发现同步失败,缓存中的数据并没有被修改,这个问题是事务隔离级别导致的,通过hibernate可以修改默认的事务隔离级别。
在Hibernate中可以设置事务隔离级别:
0:TRANSACTION_NONE 不支持事务
1:TRANSACTION_READ_UNCOMMITTED 可以读取未提交的数据,这种事务隔离级别较低,会造成脏读、幻读、 不可重复读的问题
2:TRANSACTION_READ_COMMITTED 只能读取已提交的事务,这会产生幻读和不可重复读的问题
4:TRANSACTION_REPEATABLE_READ 可重复读,事务A中先查询一条数据,然后事务B修改了数据并提交, 在事务A中重新查询该数据,读取到的数据是修改前的数据不会出现 不可重复读的问题
8:TRANSACTION_SERIALIZABLE 也就是所有事务只能一个个来,不能并发执行
如果没有事务隔离,对于数据库的查询可能会出现以下问题:
脏读:脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。
幻读:当事务A查询了一张表的数据总数,事务B对该表数据进行了删除或者新增并提交事务,事务A再次读取数据总数或发现多了一些或者少了一些,这就是幻读。
不可重复读:当事务A读取了一行数据,事务B修改了该行数据并提交了事务,这是事务A再次进行查询发现两次查询的结果不一致,这就是不可重复读的问题。
clear方法:清理缓存
由于拥有Session缓存机制,Hibernate将实体类对象分为了三种状态,分别是瞬时、持久、游离。
瞬时状态是指:一个java实体类对象在Session缓存中不存在并且在数据库中也不存在。
持久状态是指:一个java实体类对象在Session缓存中存在并且在数据库中也存在。
游离状态是指:一个java实体类对象在Session缓存中不存在,但是在数据库中存在。
save方法:新增数据,当实体类id与数据库已有数据主键重复时会抛出异常,save方法执行成功对象会从瞬时状态变成持久状态。
执行新增时,首先考虑主键生成方式:
如果主键是依赖自增列,自增长,序列等等自动生成方式的,那么Hibernate在执行save时,不会读取实体类id的值。
如果主键不是自增列,自增长,序列等等,那么Hibernate在新增时会使用实体类的id属性作为数据行的主键值,这时实体类的id值不能为空且不能和数据库已有的数据重复。
update方法:更新数据,更新成功对象会从游离状态变成持久状态。
1、若更新一个持久化对象,不必显示的调用update()方法,因为在调用Transaction的commit()方法时,会调用session的flush()
2、更新一个游离对象,需要显示的调用update()方法,可以将一个游离对象转换为持久化对象。
3、当 update() 方法更新一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常。
4、当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常。
saveOrUpdate方法:
如果对象是临时对象,则调用save()方法,如果对象是游离对象,则调用update()方法。
首先考虑主键生成方式:
有:实体类对象id值不等于0的则执行update,如果没有给id赋值非0的数据会执行新增,如果id赋值了但是在数据库不存在该id值会去执行更新,但是会抛出异常。
无:首先会根据id查询当前这行数据,如果数据存在则执行更新,数据不存在则执行新增。
delete方法:根据主键删除数据,删除成功对象会从持久状态或者游离状态变为瞬时状态。
注意:在删除和更新时,推荐大家先使用get或者load将数据查询出来然后,在执行update或者delete。
get方法:根据id查询数据,查询不到返回null,get方法无延迟加载。
load方法:根据id查询数据,查询不到抛出异常,load方法支持延迟加载。