我使用Spring Data with Hibernate作为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在 UPDATE之前执行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]
有人可以解释第二次选择的情况吗?我无法看到它。
答案 0 :(得分:1)
那是Hibernate进行脏检查。它会重新加载实体,将其与您正在保存的任何更改进行比较。
有几种方法可以减轻其性能影响,例如使用版本控制:Java - JPA - @Version annotation或字节码修改,以使脏检查更有效。
答案 1 :(得分:0)
在同一事务中的某些保存/删除操作之后,每次有SELECT语句时,Hibernate都会进行脏检查。进行脏检查以清除第1 /第2级缓存。粗略地说,Hibernate通过HashMap查找,包含缓存表的名称,并与请求中使用的表进行比较。