@Transactional无效 JDBC Connection @$ will not be managed by Spring # SqlSession was not registered

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:

Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’

The error may exist in wa/hj/data/transaction/mapper/TransMapper.java (best guess)

The error may involve wa.hj.data.transaction.mapper.TransMapper.insertOne-Inline

The error occurred while setting parameters

SQL: insert into trans (id,name) values (?,?)

Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’

; 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:

Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’

The error may exist in wa/hj/data/transaction/mapper/TransMapper.java (best guess)

The error may involve wa.hj.data.transaction.mapper.TransMapper.insertOne-Inline

The error occurred while setting parameters

SQL: insert into trans (id,name) values (?,?)

Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry ‘1’ for key ‘PRIMARY’

; 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中进行配置,配置如下:

增加@EnableAspectJAutoProxy

spring.aop.auto=true

开启CGLIB代理

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);
}

你可能感兴趣的:(spring)