15
事务和并发控制 ORM —— 框架 Hibernate3.3

6 事务和并发控制

Embed Size (px)

Citation preview

Page 1: 6 事务和并发控制

事务和并发控制

ORM ——框架 Hibernate3.3

Page 2: 6 事务和并发控制

www.sodi.com.cn

数据库事务的概念

事务是一组相互依赖的操作行为,如银行交易、股票交易或网上购物。事务的成功取决于这些相互依赖的操作行为是否都能执行成功,只要有一个操作行为失败,就意味着整个事务失败。例如, Tom到银行办理转账事务,把 100元钱转到 Jack的账户上,这个事务包含以下操作行为: 从 Tom的账户上减去 100元。 往 Jack的账户上增加 100元。

显然,以上两个步骤必须作为一个不可分割的工作单元。假如仅仅第一步操作执行成功,使得 Tom的账户上扣除了100元,但是第二步操作执行失败, Jack的账户上没有增加 100元,那么整个事务失败。

数据库事务是现实生活中事务的模拟,它由一组在业务逻辑上相互依赖的 SQL 语句组成。

Page 3: 6 事务和并发控制

www.sodi.com.cn

数据库事务的 ACI D特性

事务的 ACI D特性是由关系数据库管理系统来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。

数据库管理系统采用锁的机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。

Page 4: 6 事务和并发控制

www.sodi.com.cn

声明事务边界

事务的开始边界。事务的正常结束边界( COMMI T ):提交事务,永久保存被事务更新后的数据库状态。

事务的异常结束边界( ROLLBACK):撤销事务,使数据库退回到执行事务前的初始状态。

Page 5: 6 事务和并发控制

www.sodi.com.cn

两种事务模式

数据库系统支持以下两种事务模式: 自动提交模式:每个 SQL 语句都是一个独立的事务,当数据库系统执行完一个 SQL 语句后,会自动提交事务。

手工提交模式:必须由数据库的客户程序显式指定事务开始边界和结束边界。

Page 6: 6 事务和并发控制

www.sodi.com.cn

通过 Hibernate API 声明事务边界

Hibernate封装了 JDBC API 和 JTA API ,尽管应用程序可以绕过 Hibernate API ,直接通过 JDBC API 和 JTA API 来声明事务,但是这不利于跨平台开发,因此应该优先考虑一律通过 Hibernate API 来声明事务。

在 Hibernate API 中, Session和 Transaction类提供了以下声明事务边界的方法:( 1)声明事务的开始边界:

Transaction tx = session.beginTransaction( ) ;( 2)提交事务

tx.commit( ) ;( 3)撤销事务

tx.rollback( ) ;

Page 7: 6 事务和并发控制

www.sodi.com.cn

Transaction与 Session的关系(一)

( 1) Tansaction的 rollback( ) 及 Session的 close( ) 方法都会抛出 HibernateE xception,在实际应用中处理这种异常时,可以对底层的 HibernateE xception进行包装,向高层客户程序隐藏事务或关闭 Session时出现的底层异常细节。

( 2)不管事务成功与否,最后都应该调用 Session的 close( )方法来关闭 Session,所以通常在 finally代码块中关闭Session。 Session的 close( ) 方法会清空缓存,并且释放所占用的数据库连接,把它返回到连接池中。无论是在受管理环境还是不受管理环境中,都应该由应用程序负责关闭Session。

( 3)即使事务中仅包含只读操作,也应该在事务执行成功后提交事务,并且在事务执行失败时撤销事务,因为在提交或撤销事务时,数据库系统会释放事务所占用的资源,这有利于提高数据库的运行性能。

Page 8: 6 事务和并发控制

www.sodi.com.cn

Transaction与 Session的关系(二)

( 4)一个 Session可以包含多个 Transaction实例。 将一个 Session对象和多个相关的数据库事务对应的优点在于,这些事务能够重用 Session缓存中的持久化对象,避免多个相关的数据库事务重复到数据库加载相同的数据。

值得注意的是,在任何时候,一个 Session只允许有一个未提交的事务。

( 5)如果在执行 Session的一个事务时出现了异常,就必须立即关闭这个 Session,不能再利用这个 Session来执行其他的事务。

Page 9: 6 事务和并发控制

www.sodi.com.cn

并发问题

对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题,这些并发问题可归纳为以下几类: 第一类丢失更新 脏读 虚读 不可重复读 第二类丢失更新

Page 10: 6 事务和并发控制

www.sodi.com.cn

数据库的事务隔离级别

数据库系统提供了四种事务隔离级别供用户选择: Serializable:串行化 Repeatable Read:可重复读 Read Committed:读已提交数据 Read Uncommitted:读未提交的数据

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为 Read Committed,它能避免脏读,并且具有较好的并发性能。尽管它会导致不可重复读、虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

Page 11: 6 事务和并发控制

www.sodi.com.cn

在应用程序中设置事务隔离级别

JDBC数据库连接使用数据库默认的隔离级别。在 Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别都对应一个整数: 1: Read Uncommitted 2: Read Committed 4: Repeatable Read 8: Serializable

在 Hibernate中,设置事务隔离级别的属性是connection.isolation。

Page 12: 6 事务和并发控制

www.sodi.com.cn

在应用程序中采用悲观锁和乐观锁当数据库系统采用 Read Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题。在可能出现这种问题的场合,可以在应用程序中采用悲观锁或乐观锁来避免这类问题。

从应用程序的角度,锁可以分为以下两类: 悲观锁:假定当前事务操纵数据库资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。

乐观锁:假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此完全依靠数据库的隔离级别来自动管理锁的工作。应用程序采用版本控制手段来避免可能出现的并发问题。

Page 13: 6 事务和并发控制

www.sodi.com.cn

使用悲观锁解决并发问题

悲观锁有两种实现方式: 方式一:在应用程序中显式指定采用数据库系统的独占锁来锁定数据资源(前提是数据库系统必须支持 select … for update语句)。

方式二:在数据库表中增加一个表明记录状态的 LOCK“字段,当它取值为 Y“时,表示该记录已经被某个事务

“锁定;如果为 N“, 表明该记录处于空闲状态,事务可以访问它。

Page 14: 6 事务和并发控制

www.sodi.com.cn

使用乐观锁解决并发问题

利用 Hibernate的版本控制来实现乐观锁 使用 < version> 标签 使用 < timestamp> 标签

实现乐观锁的其他方法 将 < class> 标签的 optimistic-lock属性设置为 all

Page 15: 6 事务和并发控制

www.sodi.com.cn