【发布时间】:2017-01-22 14:51:25
【问题描述】:
我正在使用带有 Hibernate 的 Spring Data 作为 JPA 实现。
在某些时候,我装载了一辆车,操纵它并保存它。使用 Spring JPA-Repository 的代码如下所示:
@Entity @DynamicUpdate @DynamicInsert
public class Car{
@PostLoad
void postLoad(){ log.debug("post load"); }
@PrePersist @PreUpdate
void preSave(){ log.debug("prePersist/preUpdate"); }
/*..*/
}
@Repository
public interface CarRepository extends JpaRepository<Car, Integer>{}
@Controller
public CarController{
public void businessLogic(){
Car car = carRepo.findOne(1); // SELECT ...
log.debug("Car loaded");
car.setColor("red");
// ...
carRepo.saveAndFlush(car); // UPDATE car SET ... <-- !!!
}
}
这在所有自动化测试和 99% 的生产环境中都能正常工作。带有事务日志和 SQL 的日志大部分时间是这样的:
SQL: select ... from Car ...
Car: post load
Car loaded
Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]
Car: prePersist/preUpdate
SQL: update Car set ...
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]
只有少数情况下,hibernate 在更新之前执行 SELECT。
SQL: select ... from Car ...
Car: post load
Car loaded
Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]
SQL: select ... from Car ...
Car: post load
Car: prePersist/preUpdate
SQL: update Car set ...
Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush]
有人可以解释在什么情况下进行第二次选择吗?我看不到。
【问题讨论】:
-
不知道你的整个设置,但如果 Car 有“子对象”,那么 Hibernate 可能会选择检查这些子对象是否已经在数据库中,因此它不必保存它们也是(因为他们已经在那里)。
-
代码应该在服务中的其他东西,这将是事务性的,而不是在你的控制器中。现在您有 2 个(隐式)事务,而一切都应该在一个事务中。接下来你应该(需要)做一个
saveAndFlush,只有一个save就足够了。
标签: java spring hibernate jpa spring-data