时间
|
转账事务A
|
取款事务B
|
T1
|
|
开始事务
|
T2
|
开始事务
|
|
T3
|
|
查询账户余额为1000元
|
T4
|
|
取出500元把余额改为500元
|
T5
|
查询账户余额为500
元(脏读)
|
|
T6
|
|
撤销事务余额恢复为1000元
|
T7
|
汇入100元把余额改为600元
|
|
T8
|
提交事务
|
|
时间
|
取款事务A
|
转账事务B
|
T1
|
|
开始事务
|
T2
|
开始事务
|
|
T3
|
|
查询账户余额为1000元
|
T4
|
查询账户余额为1000元
|
|
T5
|
|
取出100元把余额改为900元
|
T6
|
|
提交事务
|
T7
|
查询账户余额为900
元(和T4
读取的不一致)
|
|
时间
|
统计金额事务A
|
转账事务B
|
T1
|
|
开始事务
|
T2
|
开始事务
|
|
T3
|
统计总存款数为10000元
|
|
T4
|
|
新增一个存款账户,存款为100元
|
T5
|
|
提交事务
|
T6
|
再次统计总存款数为10100
元(幻象读)
|
|
时间
|
取款事务A
|
转账事务B
|
T1
|
开始事务
|
|
T2
|
|
开始事务
|
T3
|
查询账户余额为1000元
|
|
T4
|
|
查询账户余额为1000元
|
T5
|
|
汇入100元把余额改为1100元
|
T6
|
|
提交事务
|
T7
|
取出100元把余额改为900元
|
|
T8
|
撤销事务
|
|
T9
|
余额恢复为1000
元(丢失更新)
|
|
时间
|
转账事务A
|
取款事务B
|
T1
|
|
开始事务
|
T2
|
开始事务
|
|
T3
|
|
查询账户余额为1000元
|
T4
|
查询账户余额为1000元
|
|
T5
|
|
取出100元把余额改为900元
|
T6
|
|
提交事务
|
T7
|
汇入100元
|
|
T8
|
提交事务
|
|
T9
|
把余额改为1100
元(丢失更新)
|
|
隔离级别
|
脏读
|
不可
重复读
|
幻象读
|
第一类丢失更新
|
第二类丢失更新
|
READ UNCOMMITED
|
允许
|
允许
|
允许
|
不允许
|
允许
|
READ COMMITTED
|
不允许
|
允许
|
允许
|
不允许
|
允许
|
REPEATABLE READ
|
不允许
|
不允许
|
允许
|
不允许
|
不允许
|
SERIALIZABLE
|
不允许
|
不允许
|
不允许
|
不允许
|
不允许
|
一、 数据库事务概念
数据库事务的特征: ACID
Atomic (原子性)、 Consistency (一致性)、 Isolation (隔离性)和 Durability (持久性)。 DBMS 用日志来保证数据的原子性、一致性和持久性;用锁的机制来保证数据的隔离性。
二、 事务的边界
数据库支持 2 种事务模式:自动提交和手动提交。
JDBC API 的事务边界
Hibernate API 声明事务边界
注:一个 session 可以对应多个事务,但是推荐的做法是一个 session 对应一个事务。
三、 多事务的并发问题
当多个事务同时访问相同的数据的时候,程序如果没有采取适当的隔离措施,就会发生数据库的并发问题。常见的并发问题有:
第一类丢失更新:撤消事务的时候,把其他的事务已经提交的数据给覆盖了;
脏读;读了没有提交的数据;
虚读:一个事务读到另外一个事务已经提交的新插入的数据;
不可重复读:一个事务读到另外一个事务已经提交的更新的数据;
第二类丢失更新:一个事务覆盖另外一个事务已经提交的更新数据。
四、 锁
一般地,大型的 DBMS 都会自动的管理锁定机制,但是在对数据的安全性、完整性和一致性有特殊要求的地方,可以由事务本身来管理琐的机制。
有一点要关注的是:锁的粒度越大,隔离性越好,并发性越差。
按照锁的程度来分有:
共享锁:用读操作,非独占的,其他事务可以读,但是不能更新,并发性好;
独占锁:用与 insert update 和 delete 等语句,其他事务不能读,也不能改,并发性差;
更新锁:执行 update 的时候,加锁。
死琐:多是事务分别锁定了一个资源,又请求锁定对方已经锁定的资源,就造成了请求环。
降低死锁的最好办法是使用短事务。
五、 数据库的事务隔离级别
数据库提供 4 种事务隔离级别:
Serializable :串行化;(隔离级别最高) 1
Repeatable Read :可重复读; 2
Read Commited :读已提交数据; 4
Read Uncommited :读未提交数据;(隔离级别最低) 8
Hiberate 中的隔离级别的设置
在 Hibernate 的配置文件中 hibernate.connection.isolation=2
六、 悲观锁和乐观琐
从应用程序的角度来看,锁分为悲观锁和乐观锁。
悲观锁:显示的为程序加锁,但是降低并发性。
Select ……. For update;
在 Hibernate 中的代码
Session.get(Account.class,net Long(1),LockMode.UPGRADE) ; // 程序采用悲观锁
乐观锁:依靠 DBMS 来管理锁,程序依靠版本控制来避免并发问题。
在对象 - 关系映射的文件中,用