`

精通hibernate学习笔记(4)[操作持久化对象]

阅读更多

1、理解Session的缓存

如果希望一个java对象一直处于生命周期中,就必须保证至少有一个变量引用它,或者在一个java集合中存放这个对象的引用。Session接口的实现类SessionImpl中定义了一系列的Java集合,这些java集合构成了Session的缓存。当Session的save方法持久化一个 A对象时,A对象被加入到Session的缓存中,当load方法试图从数据库中加载一个A对象时,Session先判断缓存是否已经存在这个对象,如果存在就不会去检索。调用Session.close才会清空缓存。
      session的缓存的作用:
      a.减少访问数据库的频率,提高数据访问性能。
      b.保证缓存中的对象与数据库中的相关记录保持同步,位于缓存中的对象被称为持久化对象。当缓存中的持久化对象状态发生变化,session并不会立即执行相关的SQL语句,这使得Session能够把几条相关的SQL合并为一条SQL,以便减少访问数据库的次数。(比如多次修改,只执行一次更新)
      c.当缓存中的持久化对象之间存在循环关联关系时,session会保证不出现访问对象时的死循环,以及由死循环引起的JVM堆栈溢出异常。
     session清理缓存时,执行SQL语句的顺序:
     a.按照调用session.save方法的先后顺序,执行所有对实体进行插入的insert语句。
     b.执行对实体的update语句
     c.执行对集合的delete语句
     d.执行对集合元素进行delete,update或insert的SQL语句。
     e.执行对集合的insert语句。
      f.按照session.delete方法的先后顺序,执行对实体的delete语句

     默认情况下,清理缓存的时间点:
     a.当应用程序调用Transaction.commit()方法时,commit()方法先清理缓存,再提交事务。
     b.当应用程序调用session的find或iterate时,如果缓存中持久化对象地属性发生了变化,就会清理缓存,以保证查询结果能反映持久化对象地最新状态。
     c.调用session.flush方法。
      注:flush与commit的区别,flush清理缓存但是不提交事务。
      session.setFlushMode方法,设定清理缓存的时间点。FlushMode设定了三种模式:

     flush方法适用于以下场合:
     a.插入、删除、或更新某个持久化对象会引发数据库中的触发器
     b.在应用程序中混合使用Hibernate API和JDBC API.
     c.JDBC驱动模式不健壮,导致HIbernate在自动清理缓存的模式下无法正常工作。

2、在Hibernate应用中Java对象的状态

     对于需要被持久化的java对象,在他的生命周期中,可以处于以下三个状态之一:
     a. 临时状态(transient):刚刚用new创建,还没有被持久化,不处于session的缓存中,处于该状态的对象被称为临时对象。
     b.持久化状态(persistent):已经被持久化,加入到Session缓存中,处于该状态的对象称为持久化对象。
     c. 游离状态(detached):已经被持久化,但不再处于session的缓存中,处于该状态的对象称为游离对象。(如缓存被清空,但是外部还有对其的引用)
    注:持久化类与持久化对象的区别,持久化类的实例可以处于三种状态中的任何一种,其中处于持久化状态的实例叫做持久化对象。

     2.1 临时对象的特征
          a. 不处于session的缓存中,也可以说不被任何session实例关联
          b.在数据库中没有对应的记录
          进入临时状态的条件
          a. new语句创建,此时不与数据库中任何记录对应。
          b. session.delete方法,使持久化或游离对象变为临时对象。

    2.2 持久化对象的特征
          a. 位于一个session实例的缓存中,总被一个session实例关联
          b. 与数据库中的纪录对应。
          c. session在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库。

          注:在实际应用中,应该避免一个java对象同时被多个session实例关联,这样会导致重复执行sql语句,并容易出现并发问题。

    2.3 游离对象的特征
          a. 不再位于session的缓存中,不被session关联
          b. 游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与他对应的记录(前提是没有其他程序删除)

3、session的保存、更新、删除和查询方法

    3.1 session.save方法
          a. 把对象加入到缓存,变为持久对象
          b. 使用映射文件指定的标识符生成器为持久化对象分配唯一的OID.如果oid存在,会重新分配一个OID,也就是会插入一条新的记录。
          c. 计划执行一个insert语句,但是不会立即执行,只有在清理缓存的时候才会执行。

    3.2 session.update方法
          a. 把对象重新加入的sessin的缓存中,使它变为持久化对象
          b. 计划执行一个update语句。也是在清理缓存时才会执行。
          如果希望当修改了对象的属性时才执行update语句,可以这样设置:
          <class name="mypack.Customer" table="CUSTOMERS" select-before-update="true">
          这样Update前会先查询,比较记录是否一致,不一致才进行update

    3.3 session.saveOrUpdate方法
          如果传入的参数是临时对象,调用save方法,如果传入的参数是游离对象,调用update方法,如果传入的是持久化对象,就直接返回。
          判断临时对象的方法,满足其一即可:
          a. OID=null
          b. 具有version属性并取值为null
          c. 在映射文件中为<id>元素设置了unsaved-value属性,并且OID取值与该属性值匹配
          d. 定义了Hibernate的Interceptor实现类,并且Interceptor的isUnsaved方法返回Boolean.TRUE.

    3.4 session.load和session.get方法
          区别在于:当不存在于OID对应的记录时,load方法抛出ObjectNotFoundException异常,而get方法返回null。通过查询方法获得的对象,都位于当前Session的缓存中,因此当修改了对象的属性后,session清理缓存时会同步更新数据库。

    3.5 session.delete方法
         delete方法,用于从数据库中删除与java对象对应的记录,如果传入的参数是持久化对象,session就计划执行一个deleet语句,如果传入的是游离对象,先使游离对象被session关联,变为持久化对象,然后计划执行一个delete语句,同样在清理缓存的时候才会执行delete语句。只有调用close方法时才会从session的缓存中删除该对象。

4、与触发器协同工作

hibernate与触发器协同工作带来的问题:
a. 触发器使session的缓存中的数据与数据库不一致:
原因: 触发起运行在数据库中,它执行的操作对Session是透明的。
解决方法: 在触发触发器的操作后调用session.flush和session.refresh方法,迫使session的缓存与数据库同步。
b.Session的update方法盲目的激发触发器
原因: update和saveOrUpdate都能使游离对象和session重新关联,由于session中不存在该对象快照,所以session一定会执行 update语句,这样一定会激发触发器。如果对象的数据与数据库的数据一致,这次操作是不需要的,激发触发器也是无意义的。
解决方法: 在<class>元素中设置select-before-update="true",这样数据不一致才会update.

5.使用拦截器(Interceptor)生成审计日志

使用触发器也能生成审计日志,但是它不具备跨平台特点。而hibernate的interceptor不依赖于数据库平台。
审计系统主要包括以下几个接口和类:
5.1 Auditable接口
凡是需要审计的持久化类都应该实现该接口
5.2 AuditLogRecord类
代表具体的审计日志
5.3 AuditLogInterceptor类
代表具体的拦截器
5.4 AuditLog类
该类的logEvent()静态方法生成审计日志,该方法并不是直接使用传入的session对象,因为它刚刚flush(),状态不稳定,不能用来生成审计日志。他通过该session获得数据库连接,再用这个连接新建一个临时session对象,该方法没有声明事务边界,他执行的操作仍是已存在事务的一部分。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics