spring @Transactional 声明式事务
项目地址:git@github.com:witaste/transaction-annotation.git
情景一:
A external method calls a method of the target object
外部方法调用目标对象的事务方法,异常逐层抛出,最终由a() 抛出,可以回滚。
@Service public class FooServiceImpl implements FooService { @Autowired private FooMapper fooMapper; @Transactional(propagation = Propagation.REQUIRED) public void a() { b(); } public void b() { fooMapper.insert(new Foo("1")); int i = 1 / 0; fooMapper.insert(new Foo("2")); } }
情景二:
The target object call another method of the target object
不能开启事务,插入了一条数据。
@Service public class FooServiceImpl implements FooService { @Autowired private FooMapper fooMapper; public void a() { try { b(); } catch (Exception e) { System.out.println(e.getMessage()); } } @Transactional(propagation = Propagation.REQUIRED) public void b() { fooMapper.insert(new Foo("1")); int i = 1 / 0; fooMapper.insert(new Foo("2")); } }
情景二解决办法:
办法1.
将b() 转移到OtServiceImpl 中即可。
办法2.
使用代理对象调用b() , 即:
((FooService) AopContext.currentProxy()).b();
需要引入jar包
<!-- aspectj --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
需要暴露代理:
<aop:aspectj-autoproxy expose-proxy="true"/>
修改后的类:
@Service public class FooServiceImpl implements FooService { @Autowired private FooMapper fooMapper; public void a() { try{ ((FooService) AopContext.currentProxy()).b(); }catch(Exception e){ System.out.println(e.getMessage()); } } @Transactional(propagation = Propagation.REQUIRED) public void b() { fooMapper.insert(new Foo("1")); int i = 1 / 0; fooMapper.insert(new Foo("2")); } }
PS:其他复杂情景不做考虑
附运行日志:
情景一:
16:02:27.372 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 16:02:27.372 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:02:27.403 [main] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] will be managed by Spring 16:02:27.403 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ooo Using Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] 16:02:27.403 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Preparing: select sys_guid() from dual 16:02:27.513 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Parameters: 16:02:27.872 [main] DEBUG cn.zno.dao.FooMapper.insert - ooo Using Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] 16:02:27.872 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Preparing: insert into FOO (ID, NAME) values (?, ?) 16:02:27.872 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Parameters: 220CFD8EE4A60CF3E053433210AC3DFB(String), 1(String) 16:02:27.903 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:02:27.950 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:02:27.950 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d]
情景二:
16:09:12.544 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
16:09:12.544 [main] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@db15e1] was not registered for synchronization because synchronization is not active
16:09:12.622 [main] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [24683438, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] will not be managed by Spring
16:09:12.622 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ooo Using Connection [24683438, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver]
16:09:12.622 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Preparing: select sys_guid() from dual
16:09:12.732 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Parameters:
16:09:12.794 [main] DEBUG cn.zno.dao.FooMapper.insert - ooo Using Connection [24683438, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver]
16:09:12.794 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Preparing: insert into FOO (ID, NAME) values (?, ?)
16:09:12.794 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Parameters: 220D15B5E3891024E053433210AC7FE0(String), 1(String)
16:09:12.841 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@db15e1]
/ by zero
情景二改:
16:12:13.466 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession 16:12:13.482 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:12:13.513 [main] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] will be managed by Spring 16:12:13.513 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ooo Using Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] 16:12:13.513 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Preparing: select sys_guid() from dual 16:12:13.622 [main] DEBUG c.zno.dao.FooMapper.insert!selectKey - ==> Parameters: 16:12:13.685 [main] DEBUG cn.zno.dao.FooMapper.insert - ooo Using Connection [33362707, URL=jdbc:oracle:thin:@//172.16.50.67:1521/orcl, UserName=E_CHANNEL, Oracle JDBC driver] 16:12:13.685 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Preparing: insert into FOO (ID, NAME) values (?, ?) 16:12:13.685 [main] DEBUG cn.zno.dao.FooMapper.insert - ==> Parameters: 220D207E0A56111CE053433210ACAD95(String), 1(String) 16:12:13.716 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:12:13.747 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] 16:12:13.747 [main] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14d3d6d] / by zero
补充说明:
如果需要定义业务异常控制事务回滚,切记要用runtime exception
(rolling back on RuntimeException and Error but not on checked exceptions).