Spring中的存储库和事务并存。 Spring中的所有数据库访问都应在事务内运行,并且通常在某个地方使用@Transactional
来强制执行此操作。 但是,这并非总是必要的。 例如,当使用Spring Data时,您的存储库使用SimpleJPARepository
来实现CRUD功能。 SimpleJPARepository
使用@Transactional
因此在执行CRUD操作时,已经为您处理了事务。 这可能会给人以错误的印象,即您不需要使用@Transactional
注释自己的类,因为仅当您知道自己在做什么时,这才是正确的。
考虑以下基于Spring Data的时间序列示例来管理汽车租赁:
public CarRentalEntry createNewRental(Car car) {CarRentalEntry latestEntry = carRentalRepository.findByCarId(car.getId());latestCarRentalEntry.setEndDate(LocalDate.now());CarRentalEntry newEntry = new CarRentalEntry();newEntry.setCarId(car.getId())newEntry.setStartDate(LocalDate.now());newEntry.setEndDate(null);carRentalRepository.save(newEntry);
}
在上面的示例中,通过存储库获取了特定汽车的最新租车条目,并结束了该租车条目。 然后,将创建并保存一个新的汽车租赁条目。 由于carRentalRepository
是一个处理事务的SimpleJPARepository
,因此无需@Transactional
carRentalRepository
可以使用。 现在考虑在更改latestEntry
的结束日期之前进行保存的以下latestEntry
:
public CarRentalEntry createNewRental(Car car) { CarRentalEntry newEntry = new CarRentalEntry();newEntry.setCarId(car.getId())newEntry.setStartDate(LocalDate.now());newEntry.setEndDate(null);carRentalRepository.save(newEntry);CarRentalEntry latestEntry = carRentalRepository.findByCarId(car.getId());latestCarRentalEntry.setEndDate(LocalDate.now());}
从功能上讲,该方法完全相同,但是在此示例中,将仅执行保存 。 因为没有事务,对latestEntry
修改将不会保存到数据库中! 为了使这种方法有效,必须使用@Transactional
注释createNewRental()
。 如果JPA受管实体上的任何更改发生在正常JPA行为的事务内,则仅将其自动保存。 因此,问题在于为什么第一种方法不需要交易。
实际上确实如此。 当latestEntry
是通过存储库读取,它被加入到persistanceContext
JPAS的(又名1级高速缓存) entityManager
。 当调用save()
方法时,它在事务提交时刷新了persistanceContext
,这反过来又带来了副作用,即还保留了修改后的latestEntry
。 在第二个示例中, persistanceContext
latestEntry
在调用save()
时没有latestEntry
。 因为在方法完成时没有事务提交,所以不会刷新更改。 通过添加@Transactional
,再次刷新persistanceContext
,并将修改内容写入数据库。 请注意,第二个示例也可以通过调用carRentalRepository.flush()
@Transactional
,因为它也可以在@Transactional
下运行。
最重要的是,您应该控制自己的事务,因为这种情况表明容易出错。
最后是调试Hibernate和受管实体问题时的提示。 放置断点的良好候选类是:
-
org.springframework.orm.jpa.JpaTransactionManager
-
org.hibernate.jpa.internal.TransactionImpl.commit()
要刷新的持久性上下文通常在TransactionImpl.entityManager.session.persistenceContext
找到
翻译自: https://www.javacodegeeks.com/2018/05/automatic-save-of-managed-jpa-entities-outside-of-transaction.html