[事务简介:] https://www.cnblogs.com/caoyc/p/5632963.html
1. 事务隔离带来的问题
更新丢失:两事务同时更新,一个失败回滚覆盖另一个事务的更新。或事务1执行更细操作,在事务1结束前事务2也更新,则事务1的更细结果被事务2的覆盖了。
脏读:事务T2读取到事务T1修改了但是还未提交的数据,之后事务T1又回滚其更新操作,导致事务T2读到的是脏数据。
不可重复读:事务T1读取某个数据后,事务T2对其做了修改并且提交,当事务T1再次读该数据时得到与前一次不同的值。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了
虚读(幻读):事务T1读取在读取某范围数据时,事务T2又插入一条数据,当事务T1再次数据这个范围数据时发现不一样了,出现了一些“幻影行”
2. 事务隔离级别(Isolation)
1. 读未提交(Read Uncommitted)
含义解释:只限制同一数据写事务禁止其他写事务。解决”更新丢失”。(一事务写时禁止其他事务写)
名称解释:可读取未提交数据
所需的锁:排他写锁
Oracle
不支持此事务级别
2. 读提交(Read Committed)
含义解释:只限制同一数据写事务禁止其它读写事务。解决”脏读”,以及”更新丢失”。(一事务写时禁止其他事务读写)
名称解释:必须提交以后的数据才能被读取
所需的锁:排他写锁、瞬间共享读锁
MVCC:快照版本是该行
的最新一条快照版本
3. 可重复读(Repeatable Read)
含义解释:限制同一数据写事务禁止其他读写事务,读事务禁止其它写事务(允许读)。解决”不可重复读”,以及”更新丢失”和”脏读”。(一事务写时禁止其他事务读写、一事务读时禁止其他事务写)
注意没有解决幻读,解决幻读的方法是增加范围锁(range lock)或者表锁
名称解释:能够重复读取
所需的锁:排他写锁、共享读锁
解惑:MySQL的InnoDB引擎
在此隔离级别下,通过MVCC
解决了不可重复度
和幻读
2个问题,因此很难模拟出(不过事务内insert重复数据的时候还是可以看到幻读的场景)
MVCC:快照版本是事务开始时的版本
4. 串行化(Serializable)
含义解释:限制所有读写事务都必须串行化实行。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。(一事务写时禁止其他事务读写、一事务读时禁止其他事务读写)
所须的锁:范围锁或表锁
事务A:读行r | --------------- | 读行r
事务B:--------| 写r commit |
READ COMMITTED:读的是事务B提交后
的快照
REPEATABLE READ:读的是事务A开始时
读的快照。
3. 事务属性,传播行为
1. Required(spring transaction 默认值)
必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务
2. RequiredNew
创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)
3. Supports
支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行
4. NotSupported
不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行
5. Mandatory
必须有事务,否则抛出异常,使用PROPAGATION_MANDATORY指定,使用当前事务执行,如果当前没有事务,则抛出异常(IllegalTransactionStateException)。当运行在存在逻辑事务中则以当前事务运行,如果没有运行在事务中,则抛出异常
6. Never
不支持事务,如果当前存在是事务则抛出异常,使用PROPAGATION_NEVER指定,即以非事务方式执行,如果当前存在事务,则抛出异常(IllegalTransactionStateException)
7. Nested
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
Nested和RequiresNew的区别:
- RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;
- Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;
- Nested使用JDBC 3的保存点(save point)实现,即如果使用低版本驱动将导致不支持嵌套事务
4. 事务模型
4.1 本地事务模型
使用本地资源管理器(local resource manager)进行管理,实际上管理的是连接
,而不是事务
实际上由DBMS
和JMS
的提供者进行管理
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
conn.begin();
try {
conn.commit();
} catch() {
conn.rollback();
}
4. 2 编程事务模型
利用Java事务API(JTA)
请求提供商提供的Java事务服务(JTS)
,利用javax.transaction.UserTransaction接口进行编程事务
管理,而不是连接
要注意异常的捕获,很麻烦,而且事务没有传播性
UserTransaction txn = sessionCtx.getUserTransaction();
txn.begin();
try {
txn.commit();
} catch() {
txn.rollback();
}
4.3 声明(容器托管)事务模型
软件框架或则容器管理了事务的开始和结束,事务的传播属性,事务的隔离级别,回滚条件
@Transactional(rollbackFor = Exception.class,
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED
)
支持隔离传播属性:
read设置为supports
,write设置为required/mandatory
,如果异常不负责回滚事务,使用mandatory
REQUIRED,REQUIRED_NEW,MANDATORY
SUPPORTS,NOT_SUPPORTED,NEVER
支持隔离级别: 隔离性
= 并发性
+一致性
READ_UNCOMMITED,READ_COMMITED
REPEATABLE_READ,SERIALIZEABLE
Java事务服务(JTS):
异构系统实现分布式事务交互
5 事务设计模式
5.1 客户端拥有事务
客户端控制 begin/commit/rollback
然后组件设置传播为mandatory
并且不处理try{}catch(){}
**不建议使用**
5.2 领域服务拥有事务
服务端提供每个领域的服务,集中管理事务