【问题标题】:Spring Boot + JPA + Hibernate does not commit when repository.saveSpring Boot + JPA + Hibernate 在 repository.save 时不提交
【发布时间】:2023-03-21 18:59:01
【问题描述】:

我有一个带有 MySQL 的 Spring Boot 应用程序 + JPA。在我的控制器中,当我发布一个实体时,我可以调用 repository.save,并返回“创建/更新”对象。

但是,当我查看数据库时,我发现对象没有更新。

这是我的 application.yml:

spring:
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none
    properties:
      hibernate.dialect: org.hibernate.dialect.MySQLDialect
      org.hibernate.envers.store_data_at_delete: true
      org.hibernate.envers.global_with_modified_flag: true
      org.hibernate.envers.track_entities_changed_in_revision: true
  datasource:
    initialize: false
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:databaseName}?createDatabaseIfNotExist=true
    username: ${DB_USERNAME:root}
    password: ${DB_PASSWORD:root}
    driver-class-name: com.mysql.jdbc.Driver
    hikari:
      minimumIdle: 20
      maximumPoolSize: 30
      idleTimeout: 5000
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048

你知道我还需要做什么吗?

这是我的控制器:

@RequestMapping(method = RequestMethod.POST, produces = "application/json")
public MyEntity saveMyEntity(@Valid @RequestBody final MyEntity myEntity) {
    Assert.notNull(myEntity, "The entry cannot be null");
    return myEntityService.save(myEntity);
}

还有我的实体服务:

@Override
@UserCanCud
public Entity save(final Entity entity) {
    Assert.notNull(entity);
    final Entity savedEntity = repository.save(entity);
    return savedEntity;
}

【问题讨论】:

  • 添加调用保存的控制器方法
  • 帖子已编辑。我希望它很清楚
  • 你的交易边界在哪里?
  • 嗨斯特凡,我不明白你的问题。你的意思是如果我有用 @Transactional 注释的方法?
  • 为了持久化/更新你需要在一个事务中。当你使用注释时,一个方法应该用@Transactional标记

标签: hibernate jpa spring-boot commit


【解决方案1】:

在我的(有限的)经验中,由于 Spring 幕后发生的魔力,这些类型的问题更难调试,但我会尝试提供一些帮助我解决类似问题的建议 - 希望这为您提供所需的轻推。

@Transactional 表示法建立了一个事务 范围,该范围指示事务何时开始和结束,也称为边界。如果您在此边界之外操作,您将收到错误或无法按预期工作。

首先,我发现这段文档对 Spring 事务最有帮助:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html 特别是 this section

其次,您可能希望启用跟踪级别日志和可能的 SQL 语句来帮助调试。为此,我将以下内容添加到我的 application.properties - 您可以将其添加到您的 application.yml 中,并进行一些小的调整

spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type=trace
spring.jpa.show-sql=true
logging.level.org.hibernate=TRACE

这里会有很多输出,但你会很好地了解幕后发生的事情。

第三,对我来说,学习如何使用@Transactional 最重要的部分是每次对 DAO 的调用都会创建一个新会话 - 或者 - 如果在相同的事务范围内,则重用现有会话。有关此示例,请参阅上面的文档。

现在,我怀疑当您读回更新的对象时,您的事务仍然被认为是打开的。尝试在您的保存方法中执行flush,看看这是否有助于将您的更改保留回数据库。

希望您能够使用上面的资源在不进行过多搜索的情况下找到问题,如果不是,您至少应该有一些更完整的信息来说明持久性不持久的原因。

【讨论】:

  • 嗨罗伯特,感谢您的评论,在您发表评论之前,我已经尝试过更详细地了解幕后发生的事情,但我仍然无法让它发挥作用。只是另一个评论,当创建实体(id 为空)时,事务完成......我可以看到插入语句,但是当我尝试更新实体时却看不到。
  • 如果您使用repository.find() 搜索实体并更新返回的实体会发生什么情况?
  • 嗨罗伯特,我试过你说的,这样做,repository.findOne(myEntity.getId),然后是 myEntity.setOneField(newValue); repository.save() 还是没有保存....
  • 好的 - repositoryEntityManager 的实例,还是您的 RepositoryImpl 的实例,其中包含 EntityManager?假设它是你的RepositoryImpl,是save() 调用entityManager.merge(entity) 还是调用persist()
  • 既然您已经尝试过详细输出,我猜保存后没有 SQL UPDATE?如果没有,您可能真的需要更深入地调试实现以查看问题所在。
【解决方案2】:

我认为您的问题在于您使用注释 @UserCanCud 进行的拦截。

我刚刚使用您建议的相同设置创建了一个项目,并且它可以正常工作。看看:

https://github.com/nitzap/spring-data-mysql

如果我遗漏了什么,请告诉我。

【讨论】:

  • 嗨德语,嗯,奇怪,因为我尝试删除注释,还有方面,但仍然没有更新。
  • 你可以试试我发给你的例子。我们可以确定问题出在您的项目之外。
【解决方案3】:

要保存您的对象,您需要设置正确的 jpa 配置和存储库,之后它将被保存。

例如,我们有如下的用户实体和 userRepository

User Enity Class

package com.sanjeev.domain;

import javax.persistence.*;

@Entity(name = "user")
@Table(name = "user")
public class User {

    @Id
    @Column(name = "id")
    private Long id;
    @Column(nullable = false)
    private String username;
    @Column(nullable = false)
    private String email;
    @Column(nullable = false)
    private String password;

 //getters and setters   
}

User Repository class

package com.sanjeev.repository;    
    import com.sanjeev.domain.User;
    import org.springframework.data.jpa.repository.JpaRepository;

    public interface UserRepository extends JpaRepository<User, Long> {

    }

User Service class

package com.sanjeev.service;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.sanjeev.repository.UserRepository;
import com.sanjeev.domain.User;

@Service
public class UserService{

  @Autowired
  private UserRepository userRepository;

  public void saveUser(User user){
    userRepository.save(user);
  }


}

If you will follow above steps then your object must me saved

了解更多click here

【讨论】:

  • 嗨 sanjeevha,我不认为我做错了。我正在执行上述步骤,但仍然无法正常工作。
  • 实际上我最近在我的机器上做了它并且它工作得很好,如果你按照给定的链接,那么你可能会得到更多的想法
【解决方案4】:

我终于找到了解决方案...我尝试更新的实体上有 @Immutable 注释...

【讨论】:

    【解决方案5】:

    以防万一,如果它对任何人有帮助,我有单独的 ReadRepos 和 WriteRepos 控制器,并且使用不同的数据库(一个作为主数据库,另一个作为从属数据库)。 从技术上讲,这两个 repos 都直接或通过 JPA 存储库间接扩展 CRUD repos 都可以访问 save(Entity e) 方法。

    因此,在意外使用 readRepo 保存时,它默默地忽略了调用,而不是抛出错误。

    所以底线是,如果你有同样的情况,请确保你使用 writeRepo 来保存/更新

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 2016-03-08
      • 2019-06-12
      • 1970-01-01
      相关资源
      最近更新 更多