【问题标题】:Spring Boot Transaction RollbackSpring Boot 事务回滚
【发布时间】:2018-11-05 04:34:24
【问题描述】:

我尝试切换到 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 跟踪 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager :绑定值 [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] 为关键 [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] 线程 [http-nio-8080-exec-4] 2018-05-25 10:36:46.356 DEBUG 25041 --- [nio-8080-exec-4] c.s.knected.controller.UserController:保存 id=null 2018-05-25 10:36:46.357 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 检索值 [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] 为关键 [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] 绑定到线程 [http-nio-8080-exec-4] 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 绑定值 [org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571] 为 键 [HikariDataSource (HikariPool-1)] 到线程 [http-nio-8080-exec-4] 2018-05-25 10:36:46.358 跟踪 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 初始化事务 同步 2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor:获取 交易为 [c.s.k.service.UserServiceImp.saveUser] 2018-05-25 10:36:46.358 跟踪 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 检索值 [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] 为关键 [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] 绑定到线程 [http-nio-8080-exec-4] 休眠: 插入 进入 用户 (created_by、time_created、deleted、deleted_by、time_deleted、名称、time_updated、updated_by、地址、代码、电子邮件、密码、 first_name, lost_login, last_name, mobile, phone, photo_id, time_registered, user_type) 价值观 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'a') 2018-05-25 10: 36:46.457 跟踪 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor : 完成交易 [c.s.k.service.UserServiceImp.saveInvite] 之后 异常:c.s.k.service.ServiceException 2018-05-25 10:36:46.457 跟踪 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : 应用规则来确定 事务是否应该回滚 c.s.k.service.ServiceException 2018-05-25 10:36:46.457 跟踪 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : 获胜的回滚规则是: 带有模式的 RollbackRuleAttribute [c.s.k.service.ServiceException] 2018-05-25 10:36:46.460 跟踪 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 清算交易 同步 2018-05-25 10:36:46.460 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager:已删除 值 [org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571] 来自线程的键 [HikariDataSource (HikariPool-1)] [http-nio-8080-exec-4] 2018-05-25 10:36:46.468 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager:已删除 值 [org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2] 为 钥匙 [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71] 来自线程 [http-nio-8080-exec-4]

我还注意到,如果我将 @Transactional for Required 更改为 Mandatory:

@Transactional(propagation = Propagation.MANDATORY, rollbackFor = {ServiceException.class})

我收到以下错误:

org.springframework.transaction.IllegalTransactionStateException: 否 为标记有传播的事务找到现有事务 '强制'

以下是我的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

【问题讨论】:

  • 从哪里调用 saveUser()?我的意思是在同一个班级?如果是,这将不起作用。请参考stackoverflow.com/questions/3423972/…
  • @SundararajGovindasamy 日志清楚地表明情况并非如此,因为正在调用 TransactionInterceptor
  • 感谢您调查此问题。使用 @Autowired UserService 从 UserController 类调用 saveUser()。
  • 我也尝试将@Transactional 和 ServiceException 移至 HibernateDaoImp 类,但没有任何区别。
  • 根据日志,一切似乎都正常。这几乎就像底层连接忽略回滚而只是提交事务,或者根本没有底层事务并且一切都在自动提交。也许您可以在问题中包含 HikariCP 的配置?

标签: java hibernate spring-boot jpa transactional


【解决方案1】:

根据@Kayaman 的建议缩小到底层连接后,我发现Springboot 2.0 @Transaction doesn't get supported by org.hibernate.dialect.MySQL5Dialect。我更改为 MySQL5InnoDBDialect 并重新创建表,并且回滚按预期工作!

我应该首先发布我的数据源配置。

非常感谢@Kayaman 和@Sundararaj Govindasamy 的帮助!

【讨论】:

  • 好问题,好(自我)答案。这就是 Stackoverflow 应该更像的样子。
猜你喜欢
  • 2020-03-11
  • 2018-09-03
  • 2016-10-07
  • 2017-11-07
  • 2018-03-25
  • 2011-11-21
  • 2020-02-06
  • 1970-01-01
  • 2018-01-01
相关资源
最近更新 更多