Spring Boot + JPA + Hibernate 在 repository.save 时不提交
Spring Boot + JPA + Hibernate does not commit when repository.save
我有一个 Spring 引导应用程序 + JPA MySQL。在我的控制器中,当我 post 一个实体时,我可以调用 repository.save,并且我 return "created/updated" 对象。
但是,当我查看数据库时,我发现对象没有更新。
这是我的 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);
}
和 MyEntityService:
@Override
@UserCanCud
public Entity save(final Entity entity) {
Assert.notNull(entity);
final Entity savedEntity = repository.save(entity);
return savedEntity;
}
根据我的(有限)经验,这些类型的问题更难调试,因为 Spring 在幕后发生了魔法,但我会尝试提供一些对我有帮助的建议解决类似的问题 - 希望这能为您提供所需的帮助。
@Transactional
表示法建立了一个事务性 范围,指示事务何时开始和结束,也称为边界。如果你在这个边界之外操作,你要么会收到错误,要么事情不会按预期工作。
首先,我发现这段文档对 Spring 交易最有帮助:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html specifically 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
,看看这是否有助于将您的更改保存回数据库。
希望您能够使用上述资源找到问题而无需过多搜索,否则您至少应该了解一些更完整的信息,了解为什么持久性不持久。
我认为您的问题出在您使用注释 @UserCanCud 进行的拦截中。
我刚刚使用您建议的相同设置创建了一个项目并且它工作正常。看看:
https://github.com/nitzap/spring-data-mysql
如果我遗漏了什么,请告诉我。
要保存您的对象,您需要设置正确的 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
我终于找到了解决方案...我尝试更新的实体上有 @Immutable 注释...
以防万一,如果对任何人有帮助,我有单独的 ReadRepos 和 WriteRepos 控制器,并且使用不同的数据库(一个为主,另一个为从)。
从技术上讲,两个 repos 都直接或通过 JPA 存储库间接扩展 CRUD repos,都可以访问 save(Entity e) 方法。
因此,在不小心使用 readRepo 进行保存时,它会默默地忽略调用,而不是抛出错误。
所以最重要的是,如果你有同样的情况
,请确保你正在使用 writeRepo save/update
我有一个 Spring 引导应用程序 + JPA MySQL。在我的控制器中,当我 post 一个实体时,我可以调用 repository.save,并且我 return "created/updated" 对象。
但是,当我查看数据库时,我发现对象没有更新。
这是我的 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);
}
和 MyEntityService:
@Override
@UserCanCud
public Entity save(final Entity entity) {
Assert.notNull(entity);
final Entity savedEntity = repository.save(entity);
return savedEntity;
}
根据我的(有限)经验,这些类型的问题更难调试,因为 Spring 在幕后发生了魔法,但我会尝试提供一些对我有帮助的建议解决类似的问题 - 希望这能为您提供所需的帮助。
@Transactional
表示法建立了一个事务性 范围,指示事务何时开始和结束,也称为边界。如果你在这个边界之外操作,你要么会收到错误,要么事情不会按预期工作。
首先,我发现这段文档对 Spring 交易最有帮助:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html specifically 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
,看看这是否有助于将您的更改保存回数据库。
希望您能够使用上述资源找到问题而无需过多搜索,否则您至少应该了解一些更完整的信息,了解为什么持久性不持久。
我认为您的问题出在您使用注释 @UserCanCud 进行的拦截中。
我刚刚使用您建议的相同设置创建了一个项目并且它工作正常。看看:
https://github.com/nitzap/spring-data-mysql
如果我遗漏了什么,请告诉我。
要保存您的对象,您需要设置正确的 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
我终于找到了解决方案...我尝试更新的实体上有 @Immutable 注释...
以防万一,如果对任何人有帮助,我有单独的 ReadRepos 和 WriteRepos 控制器,并且使用不同的数据库(一个为主,另一个为从)。 从技术上讲,两个 repos 都直接或通过 JPA 存储库间接扩展 CRUD repos,都可以访问 save(Entity e) 方法。
因此,在不小心使用 readRepo 进行保存时,它会默默地忽略调用,而不是抛出错误。
所以最重要的是,如果你有同样的情况
,请确保你正在使用 writeRepo save/update