Spring 引导事务回滚
Spring Boot Transaction Rollback
我尝试切换到 Spring Boot (v2.0.1.RELEASE) 和 EntityManager。我花了一个星期的时间来研究 MySQL 异常时数据库回滚,但仍然无法弄清楚。
@Repository
public class HibernateDaoImp implements Dao {
@PersistenceContext
private EntityManager entityManager;
public <T extends AbstractEntity> T saveOrUpdate(T entity) {
if(entity.getId() == null || entity.getId().equals(0)) {
this.entityManager.persist(entity);
t = entity;
} else {
t = (T) this.entityManager.merge(entity);
}
return t;
}
}
@Service("userService")
public class UserServiceImp implements UserService {
@Autowired
protected Dao dao;
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {ServiceException.class})
public User saveUser(User user) throws ServiceException {
user = this.dao.saveOrUpdate(user);
throw new ServiceException(500, "internal error");
}
}
用户仍然保存在数据库中。这是登录:
2018-05-25 10:36:46.297 TRACE 25041 --- [nio-8080-exec-4]
.s.t.s.TransactionSynchronizationManager : Bound value
[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]
to thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.356 DEBUG 25041
--- [nio-8080-exec-4] c.s.knected.controller.UserController : save id=null 2018-05-25 10:36:46.357 TRACE 25041 --- [nio-8080-exec-4]
.s.t.s.TransactionSynchronizationManager : Retrieved value
[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]
bound to thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.358 TRACE
25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager :
Bound value
[org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571] for
key [HikariDataSource (HikariPool-1)] to thread [http-nio-8080-exec-4]
2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4]
.s.t.s.TransactionSynchronizationManager : Initializing transaction
synchronization 2018-05-25 10:36:46.358 TRACE 25041 ---
[nio-8080-exec-4] o.s.t.i.TransactionInterceptor : Getting
transaction for
[c.s.k.service.UserServiceImp.saveUser] 2018-05-25
10:36:46.358 TRACE 25041 --- [nio-8080-exec-4]
.s.t.s.TransactionSynchronizationManager : Retrieved value
[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]
bound to thread [http-nio-8080-exec-4] Hibernate:
insert
into
user
(created_by, time_created, deleted, deleted_by, time_deleted, name, time_updated, updated_by, adress, code, email, password,
first_name, lost_login, last_name, mobile, phone, photo_id,
time_registered, user_type)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'a') 2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4]
o.s.t.i.TransactionInterceptor : Completing transaction for
[c.s.k.service.UserServiceImp.saveInvite] after
exception: c.s.k.service.ServiceException 2018-05-25
10:36:46.457 TRACE 25041 --- [nio-8080-exec-4]
o.s.t.i.RuleBasedTransactionAttribute : Applying rules to determine
whether transaction should rollback on
c.s.k.service.ServiceException 2018-05-25
10:36:46.457 TRACE 25041 --- [nio-8080-exec-4]
o.s.t.i.RuleBasedTransactionAttribute : Winning rollback rule is:
RollbackRuleAttribute with pattern
[c.s.k.service.ServiceException] 2018-05-25
10:36:46.460 TRACE 25041 --- [nio-8080-exec-4]
.s.t.s.TransactionSynchronizationManager : Clearing transaction
synchronization 2018-05-25 10:36:46.460 TRACE 25041 ---
[nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Removed
value [org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571]
for key [HikariDataSource (HikariPool-1)] from thread
[http-nio-8080-exec-4] 2018-05-25 10:36:46.468 TRACE 25041 ---
[nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Removed
value [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for
key
[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]
from thread [http-nio-8080-exec-4]
我还注意到,如果我将 Required 的 @Transactional 更改为 Mandatory:
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = {ServiceException.class})
我收到以下错误:
org.springframework.transaction.IllegalTransactionStateException: No
existing transaction found for transaction marked with propagation
'mandatory'
以下是我的pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
任何帮助将不胜感激!
-ZJ
这是我在 application.properties 中的数据源设置:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytestdb?useSSL=false
spring.datasource.username=abc
spring.datasource.password=abc123
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.maximum-pool-size=50
spring.datasource.hikari.idle-timeout=1000
spring.datasource.hikari.pool-name=knected-pool
#spring.datasource.tomcat.max-wait=20000
#spring.datasource.tomcat.max-active=50
#spring.datasource.tomcat.max-idle=20
#spring.datasource.tomcat.min-idle=15
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.id.new_generator_mappings = false
根据@Kayaman 的建议缩小到底层连接后,我发现 。我更改为 MySQL5InnoDBDialect 并重新创建了表,并且回滚按预期进行!
我应该首先 post 我的数据源配置。
非常感谢@Kayaman 和@Sundararaj Govindasamy 的帮助!
我尝试切换到 Spring Boot (v2.0.1.RELEASE) 和 EntityManager。我花了一个星期的时间来研究 MySQL 异常时数据库回滚,但仍然无法弄清楚。
@Repository
public class HibernateDaoImp implements Dao {
@PersistenceContext
private EntityManager entityManager;
public <T extends AbstractEntity> T saveOrUpdate(T entity) {
if(entity.getId() == null || entity.getId().equals(0)) {
this.entityManager.persist(entity);
t = entity;
} else {
t = (T) this.entityManager.merge(entity);
}
return t;
}
}
@Service("userService")
public class UserServiceImp implements UserService {
@Autowired
protected Dao dao;
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {ServiceException.class})
public User saveUser(User user) throws ServiceException {
user = this.dao.saveOrUpdate(user);
throw new ServiceException(500, "internal error");
}
}
用户仍然保存在数据库中。这是登录:
2018-05-25 10:36:46.297 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] to thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.356 DEBUG 25041 --- [nio-8080-exec-4] c.s.knected.controller.UserController : save id=null 2018-05-25 10:36:46.357 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] bound to thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor : Getting transaction for [c.s.k.service.UserServiceImp.saveUser] 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] bound to thread [http-nio-8080-exec-4] Hibernate: insert into user (created_by, time_created, deleted, deleted_by, time_deleted, name, time_updated, updated_by, adress, code, email, password, first_name, lost_login, last_name, mobile, phone, photo_id, time_registered, user_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'a') 2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [c.s.k.service.UserServiceImp.saveInvite] after exception: c.s.k.service.ServiceException 2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : Applying rules to determine whether transaction should rollback on c.s.k.service.ServiceException 2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : Winning rollback rule is: RollbackRuleAttribute with pattern [c.s.k.service.ServiceException] 2018-05-25 10:36:46.460 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization 2018-05-25 10:36:46.460 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-8080-exec-4] 2018-05-25 10:36:46.468 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] from thread [http-nio-8080-exec-4]
我还注意到,如果我将 Required 的 @Transactional 更改为 Mandatory:
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = {ServiceException.class})
我收到以下错误:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
以下是我的pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
任何帮助将不胜感激!
-ZJ
这是我在 application.properties 中的数据源设置:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytestdb?useSSL=false
spring.datasource.username=abc
spring.datasource.password=abc123
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.maximum-pool-size=50
spring.datasource.hikari.idle-timeout=1000
spring.datasource.hikari.pool-name=knected-pool
#spring.datasource.tomcat.max-wait=20000
#spring.datasource.tomcat.max-active=50
#spring.datasource.tomcat.max-idle=20
#spring.datasource.tomcat.min-idle=15
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.id.new_generator_mappings = false
根据@Kayaman 的建议缩小到底层连接后,我发现
我应该首先 post 我的数据源配置。
非常感谢@Kayaman 和@Sundararaj Govindasamy 的帮助!