常见事务并发问题以及处理方法
1,数据库事务并发会引起那些常见问题以及对应的解决方法?
1)丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
2)脏读:一个事务读到另一个事务未提交的更新数据。
3)幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
4)不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
---------------------------------------------------------------------------
9.6. 事务隔离级别
为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
? Serializable:串行化。隔离级别最高。
? Repeatable Read:可重复读。
? Read Committed:读已提交数据。
? Read Uncommitted:读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
? Read Uncommitted: 1
? Read Committed: 2
? Repeatable Read: 4
? Serializable: 8
在hibernate.cfg.xml中设置隔离级别如下:
<session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中,如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。
9.7. 并发控制
当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题,在可能出现这种问题的场合。可以在应用程序中采用悲观锁或乐观锁来避免这类问题。
9.8. 乐观锁(Optimistic Locking)
乐观锁假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此不作数据库层次上的锁定。为了维护正确的数据,乐观锁使用应用程序上的版本控制(由程序逻辑来实现的)来避免可能出现的并发问题。
唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。
9.9. 使用版本检查(<version>)
Hibernate中通过版本号检查来实现后更新为主,这也是Hibernate推荐的方式。在数据库表中加入一个version(版本)字段,在读取数据时连同版本号一起读取,并在更新数据时比较版本号与数据库表中的版本号,如果等于数据库表中的版本号则予以更新,并递增版本号,如果小于数据库表中的版本号就抛出异常。
9.10. 使用时间戳(<timestamp>)
跟版本检查的用法相似。不再多说。
9.11. 悲观锁(Pessimistic Locking)
悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类并发问题,但是它影响并发性能,因此应该很谨慎地使用悲观锁。
为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
? Serializable:串行化。隔离级别最高。
? Repeatable Read:可重复读。
? Read Committed:读已提交数据。
? Read Uncommitted:读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
? Read Uncommitted: 1
? Read Committed: 2
? Repeatable Read: 4
? Serializable: 8
在hibernate.cfg.xml中设置隔离级别如下:
<session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中,如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。
9.7. 并发控制
当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题,在可能出现这种问题的场合。可以在应用程序中采用悲观锁或乐观锁来避免这类问题。
9.8. 乐观锁(Optimistic Locking)
乐观锁假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此不作数据库层次上的锁定。为了维护正确的数据,乐观锁使用应用程序上的版本控制(由程序逻辑来实现的)来避免可能出现的并发问题。
唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。
9.9. 使用版本检查(<version>)
Hibernate中通过版本号检查来实现后更新为主,这也是Hibernate推荐的方式。在数据库表中加入一个version(版本)字段,在读取数据时连同版本号一起读取,并在更新数据时比较版本号与数据库表中的版本号,如果等于数据库表中的版本号则予以更新,并递增版本号,如果小于数据库表中的版本号就抛出异常。
9.10. 使用时间戳(<timestamp>)
跟版本检查的用法相似。不再多说。
9.11. 悲观锁(Pessimistic Locking)
悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类并发问题,但是它影响并发性能,因此应该很谨慎地使用悲观锁。