spring中@Transactional事务不生效。在代码中用类继承了接口,并且在继承方法中调用了另一个事务方法,此时会导致事务不生效。
如果在一个方法中,调用内部方法,需要在调用内部方法时也能够进行代理,
使用
@EnableAspectAutoProxy注解开启AspectJ自动代理技术
@EnableTransactionManagement 开启注解式事务的支持
注:也可以不使用@EnableAspectAutoProxy注解开启AspectJ自动代理技术,可以在spring boot的默认配置appllication.properties中进行配置,配置如下:
spring.aop.auto=true
开启CGLIB代理
spring.aop.proxy-target-class=true
或者在xml中配置
使用方法:
1.使用使用AopContext.currentProxy()
((TransServiceImpl) AopContext.currentProxy()).result(id, name, updateId, updateName)
2.申明当前类引用调用方法
3.避开同一个类中调用@Transactional注解、
测试:
建表语句
CREATE TABLE trans
(
id
int(11) NOT NULL,
name
varchar(5) NOT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
mapper代码
@Repository
public interface TransMapper {
@Select(“select * from trans”)
List getAll();
@Insert("insert into trans (id,name) values (#{id},#{name})")
int insertOne(@Param("id") int id, @Param("name") String name);
@Update("update trans set name=#{name} where id=#{id}")
int update(@Param("id") int id, @Param("name") String name);
}
在普通service中添加@Transactional注解
@Service
public class TransService {
@Autowired
private TransMapper transMapper;
public List getAll() {
return transMapper.getAll();
}
@Transactional
public int insertUpdate(int id, String name, int updateId, String updateName) {
int result0 = transMapper.update(updateId, updateName);
int result1 = transMapper.insertOne(id, name);
return result0 + result1;
}
@Transactional
public int update() {
int result0 = transMapper.update(1, “aa”);
return result0;
}
}
@Test
public void update() {
transService.update();
}
此时update能正常执行,执行步骤
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7c112f5f] will be managed by Spring
==> Preparing: update trans set name=? where id=?
> Parameters: aa(String), 1(Integer)
< Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
此时能正常修改成功
@Test
public void add() {
int result = transService.insertUpdate(1, “b”,1,“a1”);
System.out.println(result);
}
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7c112f5f] will be managed by Spring
==> Preparing: update trans set name=? where id=?
> Parameters: a1(String), 1(Integer)
< Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030] from current transaction
==> Preparing: insert into trans (id,name) values (?,?)
==> Parameters: 1(Integer), b(String)
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
org.springframework.dao.DuplicateKeyException:
; Duplicate entry ‘1’ for key ‘PRIMARY’; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’
此时的事务能正常工作,没有更新成功
@Transactional
public int insertUpdate1(int id, String name, int updateId, String updateName) {
return innerOperation(id, name, updateId, updateName);
}
public int innerOperation(int id, String name, int updateId, String updateName) {
int result0 = transMapper.update(updateId, updateName);
int result1 = transMapper.insertOne(id, name);
return result0 + result1;
}
@Test
public void add() {
int result = transService.insertUpdate1(1, “b”,1,“a1”);
System.out.println(result);
}
这样事务也没有更新成功
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7c112f5f] will be managed by Spring
==> Preparing: update trans set name=? where id=?
> Parameters: a1(String), 1(Integer)
< Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030] from current transaction
==> Preparing: insert into trans (id,name) values (?,?)
==> Parameters: 1(Integer), b(String)
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f40030]
org.springframework.dao.DuplicateKeyException:
; Duplicate entry ‘1’ for key ‘PRIMARY’; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’
类继承接口
public interface TransServiceInterface {
int update(int id, String name, int updateId, String updateName);
}
@Service
public class TransServiceImpl implements TransServiceInterface {
@Autowired
private TransMapper transMapper;
@Transactional
@Override
public int update(int id, String name, int updateId, String updateName) {
int result0 = transMapper.update(updateId, updateName);
int result1 = transMapper.insertOne(id, name);
return result0 + result1;
}
}
@Test
public void testTrans() {
int result = transServiceImpl.update(1, “b”, 1, “a1”);
System.out.println(result);
}
此时事务能正常工作
@Transactional(rollbackFor = Exception.class)
@Override
public int update(int id, String name, int updateId, String updateName) {
return result(id, name, updateId, updateName);
}
public int result(int id, String name, int updateId, String updateName) {
int result0 = transMapper.update(updateId, updateName);
int result1 = transMapper.insertOne(id, name);
return result0 + result1;
}
此时事务能正常工作
@Override
public int update(int id, String name, int updateId, String updateName) {
return result(id, name, updateId, updateName);
}
@Transactional(rollbackFor = Exception.class)
public int result(int id, String name, int updateId, String updateName) {
int result0 = transMapper.update(updateId, updateName);
int result1 = transMapper.insertOne(id, name);
return result0 + result1;
}
此时事务没有生效,修改操作被执行了
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5922d3e9] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@14f40030] will not be managed by Spring
==> Preparing: update trans set name=? where id=?
> Parameters: a1(String), 1(Integer)
< Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5922d3e9]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@11eed657] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@14f40030] will not be managed by Spring
==> Preparing: insert into trans (id,name) values (?,?)
==> Parameters: 1(Integer), b(String)
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@11eed657]
从打印的日志可以看出创建了两个session,
此时的解决办法是:
首先加上两个注解
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableTransactionManagement
@EnableAspectJAutoProxy - 开启对AspectJ自动代理技术
@EnableTransactionManagement 开启注解式事务的支持,比如在某个公有方法中添加@Transactional
①boolean proxyTargetClass() default false;
描述:启用cglib代理,proxyTargetClass默认为false。
②boolean exposeProxy() default false;
描述:如果在一个方法中,调用内部方法,需要在调用内部方法时也能够进行代理,
注:也可以不使用@EnableAspectAutoProxy注解开启AspectJ自动代理技术,可以在spring boot的默认配置appllication.properties中进行配置,配置如下:
spring.aop.auto=true
spring.aop.proxy-target-class=true
或者在xml中配置
1.使用使用AopContext.currentProxy()
((TransServiceImpl) AopContext.currentProxy()).result(id, name, updateId, updateName)
2.申明当前类引用调用方法
@Resource
private TransServiceImpl transService;
@Override
public int update(int id, String name, int updateId, String updateName) {
return transService.result(id, name, updateId, updateName);
}
3.避开同一个类中调用@Transactional注解
@Resource
private TransService transService;
@Override
public int update(int id, String name, int updateId, String updateName) {
return transService.insertUpdate(id, name, updateId, updateName);
}