There are seven types of spring transactions as follows
- REQUIRED By default, a transaction is required, if not, create a new one
- REQUIRED_NEW requires a new transaction, new each time
- SUPPORTS supports transactions but does not enforce transactions
- NOT_SUPPORTS does not support transactions, a transaction suspends the transaction, and then wakes up after the method is executed
- MONDATORY forces a transaction, no transaction throws an exception
- NEVER The current method cannot have a transaction, otherwise an exception will be thrown
- NESTED nested transaction, whether there is a transaction or not, an internal transaction transaction will be created, the internal rollback will not be rolled back, the external rollback will be rolled back internally
test code
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest {
@Autowired UserService service;
//////////////////////////////////////////////////////////////////
// 可以发现在调用方法中有事务的话,被调用方法不会新建事务,直接执行
// 可以发现在调用方法中没有事务的话,会新建一个事务用于执行
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction1() throws Exception {
service.testRequiredNoTransaction();
}
@Test
public void testTransaction2() throws Exception {
service.testRequiredHasTransaction();
}
//////////////////////////////////////////////////////////////////
// 可以发现无论有没有事务,supports都不会去创建一个事务
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction3() throws Exception {
service.testSupportsOfHasTransaction();
}
@Test
public void testTransaction4() throws Exception {
service.testSupportsOfNoTransaction();
}
//////////////////////////////////////////////////////////////////
// 可以发现无论有没有事务,required都会创建一个事务
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction5() throws Exception {
service.testRequiredNewOfHasTransaction();
}
@Test
public void testTransaction6() throws Exception {
service.testRequiredNewOfNoTransaction();
}
//////////////////////////////////////////////////////////////////
// mandatory在没有事务的环境下会抛出异常IllegalTransactionStateException
// mandatory在由事务的环境下正常运行
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction7() throws Exception {
try {
service.testMandatoryOfNoTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction8() throws Exception {
try {
service.testMandatoryOfHasTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
//////////////////////////////////////////////////////////////////
// nested 默认会创建一个nested transaction
// 在外层事务抛出异常下,内层事务会回滚 test11
// 在内层事务抛出异常下,外层事务不会回滚 test12
//
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction9() throws Exception {
try {
service.testNestedOfNoTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction10() throws Exception {
try {
service.testNestedOfHasTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction11() throws Exception {
try {
service.testNestedOfHasTransactionWithException();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction12() throws Exception {
try {
service.testNestedOfHasTransactionWithNestedException();
}catch (Exception e){
e.printStackTrace();
}
}
//////////////////////////////////////////////////////////////////
// never在有事务的环境下会抛出异常IllegalTransactionStateException
// never在没有事务的环境下正常运行,与mandatory正好相反
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction13() throws Exception {
try {
service.testNeverOfNoTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction14() throws Exception {
try {
service.testNeverOfHasTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
//////////////////////////////////////////////////////////////////
// not_supported 在有事务的环境下会将当前事务挂起,执行完当前方法结束会再把事务唤醒
// not_supported 在没有事务的环境下直接运行。不等待
//////////////////////////////////////////////////////////////////
@Test
public void testTransaction15() throws Exception {
try {
service.testNotSupportedOfHasTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
@Test
public void testTransaction16() throws Exception {
try {
service.testNotSupportedOfNoTransaction();
}catch (Exception e){
e.printStackTrace();
}
}
}
External transaction (or called transaction caller)
@Service
public class UserService {
@Autowired
ShopService shopService;
private final UserMapper mapper;
@Autowired
public UserService(UserMapper mapper) {
this.mapper = mapper;
}
public User findByName(String name) {
return mapper.selectByPrimaryKey(name);
}
@Transactional
public int updateUser(User user) {
mapper.updateByPrimaryKeySelective(user);
Object proxy = AopContext.currentProxy();
System.out.println(proxy);
throw new BaseException("-1", "我就不想让你更新成功");
}
//////////////////////////////////////////////////////////////////////////////////////////////
public void testRequiredNoTransaction(){
//shopService.testA();
System.out.println(">>>>>>>>>>>>>>>> 我没有事务,我调用一个事务传播行为Propagation.REQUIRED,开始");
shopService.testTransaction1();
System.out.println(">>>>>>>>>>>>>>>> 我没有事务,我调用一个事务传播行为Propagation.REQUIRED,结束");
}
@Transactional
public void testRequiredHasTransaction(){
//shopService.testA();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.REQUIRED,开始");
shopService.testTransaction1();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.REQUIRED,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testSupportsOfHasTransaction(){
//shopService.testA();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.SUPPORTS,开始");
shopService.testTransactionSupports();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.SUPPORTS,结束");
}
public void testSupportsOfNoTransaction(){
//shopService.testA();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.SUPPORTS,开始");
shopService.testTransactionSupports();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.SUPPORTS,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testRequiredNewOfHasTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.REQUIRED_NEW,开始");
shopService.testTransactionRequiredNew();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.REQUIRED_NEW,结束");
}
public void testRequiredNewOfNoTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.REQUIRED_NEW,开始");
shopService.testTransactionRequiredNew();
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.REQUIRED_NEW,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testMandatoryOfHasTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.MANDATORY,开始");
shopService.testTransactionMandatory();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.MANDATORY,结束");
}
public void testMandatoryOfNoTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.MANDATORY,开始");
shopService.testTransactionMandatory();
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.MANDATORY,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testNestedOfHasTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NESTED,开始");
shopService.testTransactionNested();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NESTED,结束");
}
@Transactional
public void testNestedOfHasTransactionWithException() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NESTED,开始");
shopService.testTransactionNested();
throw new BaseException("-1", "外层调用函数抛出异常!!");
}
@Transactional
public void testNestedOfHasTransactionWithNestedException() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NESTED,开始");
User user = new User();
user.setName("wuhulala");
user.setRemark("内层事务回滚。外层事务不回滚!!!");
mapper.updateByPrimaryKeySelective(user);
try {
shopService.testTransactionNestedWithException();
} catch (Exception e){
// do nothing
}
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NESTED,结束");
}
public void testNestedOfNoTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NESTED,开始");
shopService.testTransactionNested();
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NESTED,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testNeverOfHasTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NEVER,开始");
shopService.testTransactionNever();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NEVER,结束");
}
public void testNeverOfNoTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NEVER,开始");
shopService.testTransactionNever();
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NEVER,结束");
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Transactional
public void testNotSupportedOfHasTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NOT_SUPPORTED,开始");
shopService.testTransactionNotSupported();
System.out.println(">>>>>>>>>>>>>>>> 我有事务,我调用一个事务传播行为Propagation.NOT_SUPPORTED,结束");
}
public void testNotSupportedOfNoTransaction() {
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NOT_SUPPORTED,开始");
shopService.testTransactionNotSupported();
System.out.println(">>>>>>>>>>>>>>>> 我没事务,我调用一个事务传播行为Propagation.NOT_SUPPORTED,结束");
}
}
Internal transaction (or called transaction party)
@Service
public class ShopService {
@Autowired
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void testTransaction1() {
System.out.println("我就是测试事务传播行为PROPAGATION_REQUIRED的");
System.out.println("表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)");
}
@Transactional(propagation = Propagation.SUPPORTS)
public void testTransactionSupports() {
System.out.println("我就是测试事务传播行为PROPAGATION_SUPPORTS的");
System.out.println("表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行\n" +
"\n");
}
@Transactional(propagation = Propagation.MANDATORY)
public void testTransactionMandatory() {
System.out.println("表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常");
System.out.println("我就是测试事务传播行为PROPAGATION_MANDATORY的");
}
@Transactional(propagation = Propagation.NESTED)
public void testTransactionNested() {
System.out.println("我就是测试事务传播行为PROPAGATION_NESTED的");
System.out.println("表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,\n" +
"被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。\n" +
"如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。\n" +
"如果封装事务不存在,则同PROPAGATION_REQUIRED的一样\n" +
"\n");
}
@Transactional(propagation = Propagation.NESTED)
public void testTransactionNestedWithException() {
User user = new User();
user.setName("hlx");
user.setRemark("hlx-内层事务回滚。外层事务不回滚!!!");
userMapper.updateByPrimaryKeySelective(user);
System.out.println("我就是测试事务传播行为PROPAGATION_NESTED抛出异常的");
System.out.println("表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,\n" +
"被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。\n" +
"如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。\n" +
"如果封装事务不存在,则同PROPAGATION_REQUIRED的一样\n" +
"\n");
throw new BaseException("-1", "内层事务抛出异常");
}
@Transactional(propagation = Propagation.NEVER)
public void testTransactionNever() {
System.out.println("我就是测试事务传播行为PROPAGATION_NEVER的");
System.out.println("表示当方法不应该在一个事务中运行,如果存在一个事务,则抛出异常\n" +
"\n");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testTransactionRequiredNew() {
System.out.println("我就是测试事务传播行为PROPAGATION_REQUIRES_NEW的");
System.out.println("表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。\n" +
"\n");
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testTransactionNotSupported() {
System.out.println("我就是测试事务传播行为PROPAGATION_NOT_SUPPORTED的");
System.out.println("表示该方法不应该在一个事务中运行。\n" +
"如果有一个事务正在运行,事务将被挂起,直到当前方法执行完成才恢复执行\n" +
"\n");
System.out.println("睡眠5s");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡醒了");
}
}
```java
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 如果当前线程中存在事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 判断是否和当前方法的事务行为有冲突,具体看下面解释
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
/**
* Create a TransactionStatus for an existing transaction.
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 如果当前方法不能在事务中运行,抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 如果当前方法的事务行为是NOT_SUPPORTED,挂起当前事务,执行完成之后,再次唤醒
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 如果当前方法的事务行为是REQUIRED_NEW,挂起当前事务,并新建一个事务执行,执行完之后,唤醒上个事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
}
// 如果当前方法的事务行为是NESTED,创建一个保存点。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
“`