@Service 层代码
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.DefaultTransactionDefinition; @Service @Transactional(rollbackFor = Exception.class) public class XlServiceImpl { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private XlMapper xlMapper; /** * 需求:mi()方法抛出异常,不影响本方法:本方法不回滚! * mi抛出异常后,insert1()正常插入 * @param id * @return * @throws Exception */ public String doInsert() throws Exception { xlMapper.insert1(); mi(); return "200"; } /** * 需求:本方法抛出异常时,回滚 * 抛出异常后,insert2()回滚:不插入 */ private void mi() { xlMapper.insert2(); int x = 0; int y = 3 / x; // } }
Mapper接口层代码: insert1()和insert2()的插入SQL
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Update; public interface XlMapper { @Update("UPDATE xl999 SET age=333 WHERE id=#{id}") Integer updateById(Integer id); @Insert("INSERT INTO xl (name,age,create_time) VALUES('dp1',111,NOW())") Integer insert1(); @Insert("INSERT INTO xl (name,age,create_time) VALUES('dp2',222,NOW())") Integer insert2(); }
controller层代码
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ClassForTest { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private XlServiceImpl xlServiceImpl; @GetMapping("/dosth") public String doSth() throws Exception { String affect = ""; affect = xlServiceImpl.doInsert(); return affect; } }
数据库表结构及初始数据
在spring的声明式事务@Transactional(rollbackFor = Exception.class)的类XlServiceImpl中:
需求
insert1()可以正常插入,insert2()回滚,不会插入!
实际效果
运行项目,调用方法,结果如下:
/** * 引入 (平台)事务管理器,Spring 事务策略的核心。 */ @Autowired private PlatformTransactionManager transactionManager;
/** * 需求:本方法抛出异常时,回滚 抛出异常后,insert2()回滚:不插入 */ private void mi() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务 TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态 try { xlMapper.insert2(); int x = 0; int y = 3 / x; // 手动提交事务 transactionManager.commit(status); } catch (Exception e) { // 手动回滚事务 transactionManager.rollback(status); } }
transactionManager.commit(status);
transactionManager.rollback(status);
mi()的完整代码:
/** * 需求:本方法抛出异常时,回滚 抛出异常后,insert2()回滚:不插入 */ private void mi() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务 TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态 try { xlMapper.insert2(); int x = 0; int y = 3 / x; // 手动提交事务 // transactionManager.commit(status); } catch (Exception e) { // 手动回滚事务 // transactionManager.rollback(status); } }
以上说明:真正起作用的是下面3行:
DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务 TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态
而,这3行中又起关键作用的是最后一行 :
TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态
通过第2句可知:最后一句是创建一个新事务!而这个新事务会自动完成提交和回滚,所以注释掉 提交和回滚的代码效果是一样的!!
特别注意:
DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务 TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态
这种手动方式创建的事务,在catch块中可以不用再抛出异常,也可以不用显示的写出:transactionManager.rollback(status); ,会自动进行回滚!
在方法中手动创建事务时,transactionManager.rollback(status); 最多只能执行一次,如果方法中有2个及以上地方调用的transactionManager.rollback(status); 回滚方法,那么程序就会抛出异常!如下:
在方法中如果执行了事务提交:transactionManager.commit(status); 后面再去执行事务回滚transactionManager.rollback(status);,也会报上图的错误 “事务已完成——不要再同一个事务中提交或回滚超过一次”
也就是说,不管是提交事务,还是回滚事务,二者只能有一个执行并且只能执行一次!!!
Propagation.REQUIRED | 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则自己新建事务, |
---|---|
Propagation.SUPPORTS | 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则该方法在非事务的上下文中执行 |
Propagation.MANDATORY | 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则抛出异常 |
Propagation.REQUIRES_NEW | 创建一个新的事务上下文,如果当前方法的调用者已经有了事务,则挂起调用者的事务,这两个事务不处于同一上下文,如果各自发生异常,各自回滚 |
Propagation.NOT_SUPPORTED | 该方法以非事务的状态执行,如果调用该方法的调用者有事务则先挂起调用者的事务 |
Propagation.NEVER | 该方法以非事务的状态执行,如果调用者存在事务,则抛出异常 |
Propagation.NESTED | 如果当前上下文中存在事务,则以嵌套事务执行该方法,也就说,这部分方法是外部方法的一部分,调用者回滚,则该方法回滚,但如果该方法自己发生异常,则自己回滚,不会影响外部事务,如果不存在事务,则与PROPAGATION_REQUIRED一样 |