1 多个事务并发运行时的并发问题
- 第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖;
- 脏读:一个事务读到另一个事务未提交的更新数据;
- 虚度:一个事务读到另一个事务已提交的新插入的数据;
- 不可重复读:一个事务读到另一事务已提交的更新的数据;
- 第二类丢失更新:(不可重复读特例)提交一个事务时,覆盖另一个事务已提交的更新事务。
2 锁机制保证事务隔离性
对select用共享锁,insert、update或delete采用独占锁。
3 数据库的事务隔离级别
- Serializable:串行化
- Repeatable Read :可重复读
- Read Commited:读已提交的数据(最常用)
- Read Uncommited :读未提交的数据
各隔离级别所避免的并发问题如图3-1所示:
图3-1 各隔离级别所避免的并发问题
隔离级别越高,事务的并发性能就越低,图3-2展示了隔离级别与并发性能的关系:
图3-2 隔离级别与并发性能的关系
实际应用中通常采用Read Cmmitted的隔离级别。
3.1 mysql.exe中设置隔离级别
每个数据库连接都用一个全局变量@@tx_isolation表示事务的隔离级别。默认为Repeatable Read。设置隔离级别SQL命令如下:
如果要设置数据库系统 的全局隔离级别可用如下命令:
3.2 在应用程序中设置隔离级别
JDBC连接数据库使用的是数据库系统的默认隔离级别。
Hibernate的配置文件中可以显示的设置隔离级别:
- 1:Read Uncommited
- 2:Read Committed
- 4:Repeated Read
- 8:Serializable
4 在应用程序中使用锁机制解决并发问题
由上可知,当采用Read Committed隔离级别时,回导致不可重复读和第二类丢失更新的并发问题。采用悲观锁或乐观锁解决。(优先考虑乐观锁)
悲观锁的实现方式:
- 方式一:在应用程序中显示指定采用数据库系统的独占锁来锁定数据资源。数据库默认使用共享锁来select记录。在Hibernate应用中ge加载t对象时可通过org.hibernate.LockMode指定锁定模式,对应的数据库SQL语句为select ... for update表示采用独占锁锁定查询记录
- 方式二:在表中增加一个表明记录状态的LOCK字段。
乐观锁的实现方式:
- 使用Hibernate的版本控制功能来实现(优先考虑)。在ORM映射中采用具有版本控制功能的<version>或<timestamp>元素控制。注意:这两个元素要紧跟在<id>元素后。
- 将<class>元素的optimistic-lock属性设置为“all”,dynamic-update设置为true。(只适合在一个Session中对对象操作)