原子性(Atomicity)
:将一个事务中的多个数据库操作捆绑成一个不可分割的原子单元。即对于一个事务的操作,要么全部执行,要么全部不执行。只有当整个事务的所有操作都执行成功,才会提交,否则即使整个事务中只要有一个操作失败,就算是已执行的操作也都必须都回滚到初始状态。
一致性(Consitency)
:当事务完成时,必须保证所有数据都处于一致状态,即数据不会被破坏。如从A账户转账100元到B账户,无论操作是否成功,A和B的存款总额总是不变的。
隔离性(Isolation)
:在并发操作数据时,不同的事务会有不同的数据操作,且它们的操作不会相互干扰。数据库规定了多种隔离级别,隔离级别越低,并发性越好,干扰越大会导致数据一致性变差;而隔离性越高,并发性越差,数据一致性越好。
持久性(Durability)
:一旦事务成功完成提交后,整个事务的数据都会持久化到数据库中,且结果不受系统错误影响,即使系统崩溃,也可通过某种机制恢复数据。
隔离级别
|
脏读
|
不可重复读
|
幻读
|
Read Uncommitted
|
√(允许)
|
√
|
√
|
Read Committed
|
×(不允许)
|
√
|
√
|
Repeatable Read
|
×
|
×
|
√
|
Serializable
|
×
|
×
|
×
|
事务传播行为类型
|
说明
|
PROPAGATION_REQUIRED
|
表示当前方法必须运行在事务中。若当前没有事务,则新建一个事务,若已经存在于一个事务中,则加入到这个事务中。这是最常见的选择。
|
PROPAGATION_REQUIRES_NEW
|
表示当前方法必须运行在它自己的事务中。总是会启动一个新的事务,若当前没有事务,则新建一个事务,若已经存在于一个事务中,则会将当前事务挂起。
|
PROPAGATION_NESTED
|
表示当前方法运行于嵌套事务中。若已经存在于一个事务中,则会在嵌套事务中运行(相当于子事务),且子事务不会影响父事务和其他子事务,但是父事务会影响其所有子事务;若当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
|
PROPAGATION_SUPPORTS
|
表示当前方法不需要事务上下文。如果当前没有事务,就以非事务方式执行,若已经存在于一个事务中,则加入到这个事务中。
|
PROPAGATION_NOT_SUPPORTED
|
表示当前方法不应该运行在事务中。总是以非事务方式运行,若已经存在于一个事务中,则会将当前事务挂起。
|
PROPAGATION_MANDATORY
|
表示当前方法必须在事务中运行。总是想以事务方式运行,若已经存在于一个事务中,则加入到这个事务中,若当前没有事务,则会抛出异常。
|
PROPAGATION_NEVER
|
表示当前方法不应该运行于事务上下文中。总是不想以事务方式运行,若已经存在于一个事务中,则会抛出异常,若当前没有事务,则以非事务方式运行。
|
验证Spring事务传播行为的Service层接口和实现类、验证Spring事务传播的两个Service类、以及测试方法为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
public interface iTransactionPropagation { }
@Service public class TransactionPropagationImpl implements iTransactionPropagation {
@Autowired private iServer1Service server1Service;
@Autowired private iServer2Service server2Service;
@Resource private Server1OracleDao server1OracleDao;
@Resource private Server2OracleDao server2OracleDao; }
public interface iServer1Service { }
@Service public class Server1ServiceImpl implements iServer1Service {
@Resource private Server1OracleDao server1OracleDao; }
public interface iServer2Service { }
@Service public class Server2ServiceImpl implements iServer2Service {
@Resource private Server2OracleDao server2OracleDao; }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath*:/META-INF/spring/applicationContext.xml"}) public class TransactionPropagationTest {
@Autowired private iTransactionPropagation transactionPropagation; }
|
这里针对的是
不同service类之间方法的调用
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.REQUIRED) public void saveRequired(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.REQUIRED) public void saveRequired(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.REQUIRED) public void saveRequiredException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
@Override public void noTransactionException_required_required() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequired(new Server("服务2")); throw new RuntimeException(); }
@Override public void noTransaction_required_requiredException() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequiredException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
@Override @Transactional public void transactionException_required_required() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequired(new Server("服务2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_required_requiredException() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequiredException(new Server("服务2")); }
@Override @Transactional public void transaction_required_requiredExceptionTry() { server1Service.saveRequired(new Server("服务1")); try { server2Service.saveRequiredException(new Server("服务2")); } catch (Exception e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveRequiresNew(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveRequiresNew(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveRequiresNewException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
@Override public void noTransactionException_requiresNew_requiresNew() { server1Service.saveRequiresNew(new Server("服务1")); server2Service.saveRequiresNew(new Server("服务2")); throw new RuntimeException(); }
@Override public void noTransaction_requiresNew_requiresNewException() { server1Service.saveRequiresNew(new Server("服务1")); server2Service.saveRequiresNewException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
@Override @Transactional public void transactionException_required_requiresNew_requiresNew() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequiresNew(new Server("服务2.1")); server2Service.saveRequiresNew(new Server("服务2.2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_required_requiresNew_requiresNewException() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequiresNew(new Server("服务2.1")); server2Service.saveRequiresNewException(new Server("服务2.2")); }
@Override @Transactional public void transaction_required_requiresNew_requiresNewExceptionTry() { server1Service.saveRequired(new Server("服务1")); server2Service.saveRequiresNew(new Server("服务2.1")); try { server2Service.saveRequiresNewException(new Server("服务2.2")); } catch (Exception e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.NESTED) public void saveNested(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.NESTED) public void saveNested(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.NESTED) public void saveNestedException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
@Override public void noTransactionException_Nested_Nested() { server1Service.saveNested(new Server("服务1")); server2Service.saveNested(new Server("服务2")); throw new RuntimeException(); }
@Override public void noTransaction_Nested_NestedException() { server1Service.saveNested(new Server("服务1")); server2Service.saveNestedException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
@Override @Transactional public void transactionException_Nested_Nested() { server1Service.saveNested(new Server("服务1")); server2Service.saveNested(new Server("服务2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_Nested_NestedException() { server1Service.saveNested(new Server("服务1")); server2Service.saveNestedException(new Server("服务2")); }
@Override @Transactional public void transaction_Nested_NestedExceptionTry() { server1Service.saveNested(new Server("服务1")); try { server2Service.saveNestedException(new Server("服务2")); } catch (Exception e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.SUPPORTS) public void saveSupports(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.SUPPORTS) public void saveSupports(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.SUPPORTS) public void saveSupportsException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
@Override public void noTransactionException_Supports_Supports() { server1Service.saveSupports(new Server("服务1")); server2Service.saveSupports(new Server("服务2")); throw new RuntimeException(); }
@Override public void noTransaction_Supports_SupportsException() { server1Service.saveSupports(new Server("服务1")); server2Service.saveSupportsException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
@Override @Transactional public void transactionException_Supports_Supports() { server1Service.saveSupports(new Server("服务1")); server2Service.saveSupports(new Server("服务2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_Supports_SupportsException() { server1Service.saveSupports(new Server("服务1")); server2Service.saveSupportsException(new Server("服务2")); }
@Override @Transactional public void transaction_Supports_SupportsExceptionTry() { server1Service.saveSupports(new Server("服务1")); try { server2Service.saveSupportsException(new Server("服务2")); } catch (Exception e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public void saveNotSupported(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public void saveNotSupported(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public void saveNotSupportedException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@Override public void noTransactionException_notSuppored() { server1Service.saveNotSupported(new Server("服务1")); throw new RuntimeException(); }
@Override public void noTransaction_notSuppored_notSupporedException() { server1Service.saveNotSupported(new Server("服务1")); server2Service.saveNotSupportedException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
@Override @Transactional public void transactionException_required_notSuppored() { server1Service.saveRequired(new Server("服务1")); server2Service.saveNotSupported(new Server("服务2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_required_notSupporedException() { server1Service.saveRequired(new Server("服务1")); server2Service.saveNotSupportedException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.MANDATORY) public void saveMandatory(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.MANDATORY) public void saveMandatory(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.MANDATORY) public void saveMandatoryException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
@Override public void noTransaction_Mandatory() { server1Service.saveMandatory(new Server("服务1")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
@Override @Transactional public void transactionException_Mandatory_Mandatory() { server1Service.saveMandatory(new Server("服务1")); server2Service.saveMandatory(new Server("服务2")); throw new RuntimeException(); }
@Override @Transactional public void transaction_Mandatory_MandatoryException() { server1Service.saveMandatory(new Server("服务1")); server2Service.saveMandatoryException(new Server("服务2")); }
@Override @Transactional public void transaction_Mandatory_MandatoryExceptionTry() { server1Service.saveMandatory(new Server("服务1")); try { server2Service.saveMandatoryException(new Server("服务2")); } catch (Exception e) { e.printStackTrace(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
@Service public class Server1ServiceImpl implements iServer1Service {
@Override @Transactional(propagation = Propagation.NEVER) public void saveNever(Server server) { server1OracleDao.save(server); } } @Service public class Server2ServiceImpl implements iServer2Service {
@Override @Transactional(propagation = Propagation.NEVER) public void saveNever(Server server) { server2OracleDao.save(server); }
@Override @Transactional(propagation = Propagation.NEVER) public void saveNeverException(Server server) { server2OracleDao.save(server); throw new RuntimeException(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@Override public void noTransactionException_never() { server1Service.saveNever(new Server("服务1")); throw new RuntimeException(); }
@Override public void noTransaction_never_neverException() { server1Service.saveNever(new Server("服务1")); server2Service.saveNeverException(new Server("服务2")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Override @Transactional public void transaction_never() { server1Service.saveNever(new Server("服务1")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@Override @Transactional(value = "oracleTM", isolation = Isolation.READ_UNCOMMITTED) public void readUncommittedByOracle() { System.out.println("开始 READ_UNCOMMITTED[Oracle]..."); List<Server> serverList = serverOracleDao.getAllServers(); System.out.println("serverList: " + serverList); System.out.println("结束 READ_UNCOMMITTED[MySQL]..."); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
@Service public class TimeoutImpl implements iTimeout { @Resource private Server1OracleDao server1Dao; @Resource private Server2OracleDao server2Dao;
@Override @Transactional(timeout = 2, rollbackFor = Exception.class) public void saveServer1_saveServer2_sleep() throws InterruptedException { System.out.println("\n开始保存 Server1..."); server1Dao.save(new Server("服务1")); System.out.println("结束保存 Server1...");
System.out.println("\n开始保存 Server2..."); server2Dao.save(new Server("服务2")); System.out.println("结束保存 Server2...");
System.out.println("\n开始等待..."); Thread.sleep(5000); System.out.println("结束等待..."); }
@Override @Transactional(timeout = 2, rollbackFor = Exception.class) public void saveServer1_sleep_saveServer2() throws InterruptedException { System.out.println("\n开始保存 Server1..."); server1Dao.save(new Server("服务1")); System.out.println("结束保存 Server1...");
System.out.println("\n开始等待..."); Thread.sleep(5000); System.out.println("结束等待...");
System.out.println("\n开始保存 Server2..."); server2Dao.save(new Server("服务2")); System.out.println("结束保存 Server2..."); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@Service public class ReadOnlyImpl implements iReadOnly {
@Resource private Server1OracleDao server1OracleDao;
@Resource private Server1MysqlDao server1MysqlDao;
@Override @Transactional(value = "mysqlTM", readOnly = true) public void saveServerByMysql() { server1MysqlDao.save(new Server("服务1")); }
@Override @Transactional(value = "oracleTM", readOnly = true) public void saveServerByOracle() { server1OracleDao.save(new Server("服务1")); } }
|
https://segmentfault.com/a/1190000013341344#articleHeader14
.
[3] Spring事务隔离级别简介及实例解析.
https://www.jb51.net/article/134466.htm
.
[4] MySQL的四种事务隔离级别.
https://www.cnblogs.com/huanongying/p/7021555.html
.
[5] Spring官方文档-事务.
https://docs.spring.io/spring/docs/5.0.9.RELEASE/spring-framework-reference/data-access.html#transaction
.
[6] Spring事务采坑 —— timeout.
https://blog.csdn.net/qq_18860653/article/details/79907984
.
[7] Spring 使用注解方式进行事务管理.
https://www.cnblogs.com/younggun/p/3193800.html
.