Hibernate 在保存之前执行另一个 select
Hibernate does another select before save
我有以下示例代码:
@Transactional
public void someMethod() {
MyEntity myEntity = myRepo.findById(1).orElse(null);
if (myEntity != null) {
myEntity.setValue("something");
myRepo.save(myEntity);
}
}
并且myRepo
是以下的实例:
public interface MyRepo extends CrudRepository<MyEntity, Integer> {}
所以我可以看到第一个 SELECT 来自 myRepo.findById(1)
,这是有道理的。但是当代码运行到 myRepo.save(myEntity)
时,Hibernate 不知何故认为从 findById()
返回的 myEntity
不是托管的,因此它再次执行另一个 SELECT 来创建一个托管实体,然后替换它的值使用 myEntity
,然后执行更新。
能否解释一下为什么需要另一个 SELECT 以及如何避免?此外,方法上方的 @Transactional
注释不会改变此行为,无论有无它。
它来自 @Transactional
在 Spring 中不太明显的行为。 @Transactional
意味着两件事:
- 打开持久上下文(Hibernate 会话)
- 交易本身。
你有第二个 select 因为在你的情况下 @Transactional
根本不起作用。 Hibernate 为每次调用打开一个新的持久上下文
myRepo.findById(1)
myRepo.save(myEntity)
如果您想进行自调用,您需要将对服务的引用传递给调用事务方法的方法。
class SomeServiceImpl implements SomeService {
public void doWork(SomeService self) {
self.someMethod();
}
@Transactional
public void someMethod() {
MyEntity myEntity = myRepo.findById(1).orElse(null);
if (myEntity != null) {
myEntity.setValue("something");
myRepo.save(myEntity);
}
}
}
例子
SomeService service;
service.doWork(service);
另一种方法是自动 self
到服务领域。但这不是很好,因为您必须通过归档注入使用自动软件。不可能使用构造函数进行自动化。所以很难对服务进行单元测试。
我有以下示例代码:
@Transactional
public void someMethod() {
MyEntity myEntity = myRepo.findById(1).orElse(null);
if (myEntity != null) {
myEntity.setValue("something");
myRepo.save(myEntity);
}
}
并且myRepo
是以下的实例:
public interface MyRepo extends CrudRepository<MyEntity, Integer> {}
所以我可以看到第一个 SELECT 来自 myRepo.findById(1)
,这是有道理的。但是当代码运行到 myRepo.save(myEntity)
时,Hibernate 不知何故认为从 findById()
返回的 myEntity
不是托管的,因此它再次执行另一个 SELECT 来创建一个托管实体,然后替换它的值使用 myEntity
,然后执行更新。
能否解释一下为什么需要另一个 SELECT 以及如何避免?此外,方法上方的 @Transactional
注释不会改变此行为,无论有无它。
它来自 @Transactional
在 Spring 中不太明显的行为。 @Transactional
意味着两件事:
- 打开持久上下文(Hibernate 会话)
- 交易本身。
你有第二个 select 因为在你的情况下 @Transactional
根本不起作用。 Hibernate 为每次调用打开一个新的持久上下文
myRepo.findById(1)
myRepo.save(myEntity)
如果您想进行自调用,您需要将对服务的引用传递给调用事务方法的方法。
class SomeServiceImpl implements SomeService {
public void doWork(SomeService self) {
self.someMethod();
}
@Transactional
public void someMethod() {
MyEntity myEntity = myRepo.findById(1).orElse(null);
if (myEntity != null) {
myEntity.setValue("something");
myRepo.save(myEntity);
}
}
}
例子
SomeService service;
service.doWork(service);
另一种方法是自动 self
到服务领域。但这不是很好,因为您必须通过归档注入使用自动软件。不可能使用构造函数进行自动化。所以很难对服务进行单元测试。