随笔-7  评论-24  文章-102  trackbacks-0


1、事务

1-1、类别

● 本地事务
  如果事务只和一个资源管理器有关,则为本地事物。在本地事务中,事务管理器只是将事务的管理委托给底层的资源管理器。


● 分布式事务
  分布式事务和多个可能不同的资源管理器以一种协调的方式进行交互。


1-2、Java 中事务处理

  JDBC 事务:由底层数据库事务管理器控制,操作比较简单,但是不适合控制多个应用程序组件的事务,并且没有传播的上下问。

  JTA 和 JTS:Java 事务 API 和 Java 事务服务,可以跨越多个组件和数据库使用事务。在应用程序使用 JTA 控制事务操作时,需要从 JNDI 上下文中获取 UserTranscation 和数据源。
UserTranscation ut = (UserTranscation) ctx.lookup("UserTranscation");


1-3、Hibernate 事务
 
● 基于 JDBC

  Transcation 事务对象必须从 Session 中获取,即事务必须和一个 Session 相关联。

采用 Hibernate 内置的 current session 和上下文管理。
<property name="current_session_context_class">thread</property>
...
sessionFactory.getCurrentSession().beginTranscation();


● 基于 JTA

  提供了跨 Session 的事务管理能力。
使用 SessionFactory.getCurrentSession() 方法简化事务上下文的传播,即在事务绑定 Session。


  虽然一个 Session 范围内可以存在多个事务操作,但是 Hibernate 并不支持嵌套的事务模型。
tx1
tx2
...
tx2.commit();

//数据库操作,操作无效
tx1.commit();

 


2、并发控制

 

  如果事务都是串行执行,则许多资源将处于空闲状态。为了充分利用资源,发挥数据库共享资源的优势,必须允许多个事务并发地执行。

  在单处理机系统中,事务并发执行实际上是这些并行事务轮流交叉执行,即交叉并发方式,并不是真正的并行执行。在多处理机系统中,每个处理机运行一个事务,实现事务真正意义上的并存运行,即同时并发方式。

  当多个用户并发地存取数据库时,就会产生多个事务同时存取同一数据的情况。所以,必须实现一个控制系统,使一个事务所做的修改不会对其他事务所做的修改产生负面影响,这就是并发控制。

 
2-1、封锁

  对并发操作进行的正确调度,防止并发操作破坏了事务的隔离性。采用封锁技术,事务 T 可以向系统发出请求,对某个对象例如表、记录加锁,在事务 T 释放锁之前,其他事务不能更新这些数据对象。
 
  基本的封锁有:
排他锁(Exclusive Locks,X 锁):写锁或者独占锁。
共享锁(Share Locks,S 锁):读锁。允许和其他事务一起读取数据对象D,但不能对D 做任何修改。


2-2、事务隔离

  使用封锁技术,事务对申请的资源加锁,但是会影响数据库性能。根据数据对象封锁的程度,可以分成多种不同的事务隔离级别。

  数据并发执行时,产生不一致的现象:

丢失更新(Lost Update)
  两个事务读入同一数据并修改,然后提交修改,T2 提交的结果破坏了 T1 提交的结果,导致 T1 的修改丢失。

② 不可重复读
  事务T1 读取数据后,事务T2 执行了同一数据的跟新操作,使得事务 T1 无法再现前一次读取的结果。
    事务1 读取某一数据后,事务2 对该数据作了修改,事务1 再次读取时,得到数据和前一次不一致。
    ① 事务1 读取某一些记录后,事务2 删除了同一数据源的部分数据,事务1 再次读取时,发现某些记录丢失。
    ① 事务1 读取某一些记录后,事务2 插入了同一数据源的新数据,事务1 再次读取时,发现某些记录增加。

③ 读“脏”数据
  事务T1 修改某一数据,并将其写回物理数据库。事务T2 读取同一数据后,事务T1 由于某种原因被撤销,数据库将已经修改的数据恢复原值,导致事务T2 保持的数据和数据库中的数据产生了不一致。


  ANSI SQL-99 标准定义了下列隔离级别:

● 未提交读(Read Uncommitted):隔离事务的最低级别,只能保证不会读取到物理上损坏的数据。H:1;允许产生:①②③

● 已提交读(Read Committed):常见数据库引擎的默认级别,保证一个事务不会读取到另一个事务已修改但未提交的数据。H:2;允许产生:①②

● 可重复读(Repeatable Read):保证一个事务不能更新已经由另一个事务读取但是未提交的数据。相当于应用中的已提交读和乐观并发控制。H:4;允许产生:①

● 可串行化(Serializable):隔离事务的最高级别,事务之间完全隔离。系统开销最大。H:8;允许产生:


  在数据库中,可以手工设置事务的隔离级别。
  Hibernate 在配置文件中声明事务的隔离级别,Hibenate 获取数据库连接后,将根据隔离级别自动设置数据库连接为指定的事务隔离级别。
<property name="connection.isolation">8</property>


2-3、并发控制类型

  根据使用的锁定策略和隔离等级,可以把事务的并发控制分为两种:

① 悲观并发控制
 
  用户使用时锁定数据。主要应用于数据争用激烈的环境中,以及发生并发冲突时用锁保护数据的成本低于回滚事务成本的环境中。

  Hibernate 的悲观锁定不在内存中锁定数据,由底层数据库负责完成。


② 乐观并发控制
 
  用户读取数据时不锁定数据。当一个用户更新数据时,系统将进行检查该用户读取数据后其他用户是否更改了该数据,是则产生一个错误,一般情况下,收到错误信息的用户将回滚事务并重新开始。主要用户数据争用不大,且偶尔回滚事务的成本低于读取数据时锁定数据的成本的环境中。

  Hibernate 中使用元素 version 和 timestamp 实现乐观并发控制模式的版本控制,并提供多种编程方式。版本是数据库表中的一个字段,可以是一个递增的整数,也可以是一个时间戳,它们对应 Java 持久化类的一个属性。事务提交成功后,Hibernate 自动修改版本号。如果另外一个事务同时访问同一数据,若发现提交前的版本号和事前载入的版本号有出入,则认为发生了冲突,事务停止执行,撤销操作,并抛出异常。应用程序必须捕捉该异常并做出一定的处理。

⒈应用程序级别的版本控制
⒉长生命周期会话的自动化版本控制
⒊托管对象的自动化版本控制
⒋定制自动化版本控制

 


3、Hibernate 缓存

 

  Hibernate 提供两级缓存架构,第一级缓存是 Session 内的缓存,第二级缓存是一个可插拔的缓存,能够借助第三方的组件实现。如果应用程序中经常使用同样的条件查询数据,还可以使用查询缓存来提高查询效率。

  针对缓存的范围,可以将 Hibernate 持久层缓存分为三个层次:

① 事务级缓存
 
  缓存只能被当前事务访问。缓存的生命周期以来与事务的生命周期。事务缓存由 Session 实现。一个 Session 的缓存的内容只有在本 Session 实例范围内可用。

② 应用级缓存

  缓存在某个应用范围内被所有事务共享。缓存的生命周期依赖于应用程序的生命周期。应用级缓存由 SessionFactory 实现,Session 实例由其创建,并共享其缓存。

③ 分布式缓存

  集群环境中,缓存被一个 JVM 或多个 JVM 的进程共享。分布式缓存由多个应用级的缓存实例组成,缓存中的数据被复制到集群环境中的每个 JVM 节点,JVM 间通过远程通信来保证缓存中数据的一致性。


3-1、缓存查询结果

  经常使用同样的条件查询数据,则可使用查询缓存。查询缓存需要和二级缓存联合使用,在二级缓存中,可以专门为查询缓存开辟一个命名缓存区域。查询缓存启动后将创建两个缓存区域,org.hibernate.cache.StandardQueryCache 实现保存查询结果集;org.hibernate.cache.UpdateTimestampsCache 实现保存最近更新的查询表的时间戳。

<property name="cache.use_query_cache">true</propery>

//使用查询缓存
query.setCacheable(true);

//给查询缓存指定特定的命名缓存区域
query.setCacheRegion("queryCache");

//如果其他进程更新了结果集,强行刷新缓冲区域
query.setCacheMode(CacheMode.REFRESH);

//刷新某个或全部的缓存
SessionFactory.evictQueries() 方法

 


4、高级特性

 

4-1、数据库连接池 ConnectionProvider

  J2SE 环境中使用建议。


4-2、使用数据源
  Hibernate 中,DatasourceConnectionProvider 实现了 ConnectionProvider 接口并封装了数据源的获取方法,充当了 Hibernate 和数据源间的适配器。

  J2EE 环境中使用建议。


4-3、过滤数据
 
  把公共的数据过滤条件提取出来。从 Hibernate 3.0 开始,可以利用 Hibernate Filter 对某个类或集合附加预先定义的过滤条件,在查询时过滤指定条件的数据。该过滤器是全局有效的,使用时候,还可以指定特定参数。


4-4、批量处理
 
  批量处理引发异常的根源在于缓存中保存了过多的持久化实例而耗尽内存。

① 应用程序级别的批处理

  指定 Hibernate 处理 SQL 语句时,必须积累到指定数量后再向数据库提交操作。
  <property name="jdbc.batch_size">20</property>


② 无状态 Session(StatelessSession)

  StatelessSession 接口没有持久化上下文,也不负责持久化实例的生命周期,没有一级缓存,操作也不会影响到二级和查询缓存。


③ 使用 DML 风格的 HQL 语句绕过内存直接进行数据处理

  "delete Product p where p.id > :id"


4-4、延迟加载

  设置延迟加载的属性和集合只能在该实例依附的 Session 范围内被访问,会话关闭后,实例从持久态转为托管态,再次访问该实例的一些属性时候,有可能会抛出 LazyInitializationException 异常。

① 属性延迟加载(大对象)
② 持久化类延迟加载
③ 集合延迟加载


4-5、数据抓取策略(Fetching strategies)

  可以在 Hibernate 中设定相应的数据抓取策略,减少系统产生的数据库查询操作,优化系统性能。

  在 Hibernate 中,延迟(lazy)定义了一种契约,用来表示托管状态实例中那些数据是有效的,而抓取(fetch)是用来调整 Hibernate 性能的。


4-5、监控性能
  org.hibernate.stat 包提供的工具类。



5、附录

 5-1、XML 元数据

    18.2. XML映射元数据 - Hibernate reference 3.2.0 ga 正式版中文参考手册
    18.3. 操作XML数据 (通过dom4j会话读入和更新应用程序中的XML文档)

5-2、开源工具箱

CownewStudio 是一个基于 Eclipse 的 Hibernate 正向建模辅助工具。通过它用户能以图形化的方式建立对象模型,然后根据模型生成持久化类、映射文件和数据库表。

JDBMonitor。模拟一个 JDBC 驱动来代替真正的 JDBC 驱动,截取应用程序对数据库的操作,并以合适的方式记录下来,提供性能分析的来源和依据。

 


posted on 2009-04-14 09:56 黄小二 阅读(719) 评论(0)  编辑  收藏 所属分类: S/S2SHJ2EEJ2SE

只有注册用户登录后才能发表评论。


网站导航: