Spring Data Repositories 和 JdbcTemplate 是否共享相同的事务上下文?

huangapple go评论52阅读模式
英文:

Are Spring Data Repositories and JdbcTemplate sharing the same transaction context?

问题

I struggle to find documentation on that topic.
我在寻找关于这个主题的文档时遇到困难。

I've been through Spring official transactional handling documentation, and a few SO posts that point toward a yes, but that's not what I'm seeing in practice.
我已经阅读了Spring官方事务处理文档,以及一些Stack Overflow的帖子,它们都指向肯定的方向,但实际情况并非如此。

Considering a Spring Boot application, with @EnableTransactionManagement, @EnableJpaRepositories (using Hibernate and Postgres).
考虑一个Spring Boot应用程序,使用@EnableTransactionManagement@EnableJpaRepositories(使用Hibernate和Postgres)。

I have the following code:
我有以下代码:

BusinessService:

@Transactional
public save(BuildingDTO dto) {
  var building = Building.from(dto);
  var apartments = Apartment.from(dto); 
  
  this.buildingRepository.save(building);
  this.saveAllJdbc(apartments);
}

private saveAllJdbc(List<Apartment> apartments) {
  String insertQuery = "...";
  jdbcTemplate.batchUpdate(
    insertQuery,
    apartments,
    100,
    (ps, apartment) -> // set ps values
  );
}

With the repository define as BuildingRepository extends CrudRepository<Building, UUID>, which means the save method is transactional.
使用BuildingRepository extends CrudRepository<Building, UUID>定义的存储库,这意味着save方法是事务性的。

Today my issue is that saveAllJdbc triggers the foreign key constraint, saying the referred building does not exist. Which means it is not aware of the current transaction.
今天我的问题是,saveAllJdbc触发了外键约束,说所引用的建筑不存在。这意味着它不知道当前的事务。

I made it work by either using only Spring CrudRepository methods, or only JdbcTemplate methods, in both cases, the transactions were handled as defined in the documentation.
我通过仅使用Spring CrudRepository方法或仅使用JdbcTemplate方法来使其工作,在这两种情况下,事务都是按照文档中定义的方式处理的。

Are Spring Repository default implementation and JdbcTemplate methods supposed to share the transaction context? Or is it a known limitation?
Spring Repository的默认实现和JdbcTemplate方法是否应该共享事务上下文?还是这是一个已知的限制?

英文:

I struggle to find documentation on that topic.
I've been through Spring official transactionnal handling documentation, and a few SO posts that point toward a yes, but that's not what I'm seeing in practice.

Considering a Spring Boot application, with @EnableTransactionManagement, @EnableJpaRepositories (using Hibernate and Postgres).
I have the following code:

BusinessService:

@Transactional
public save(BuildingDTO dto) {
  var building = Building.from(dto);
  var apartments = Apartment.from(dto); 
  
  this.buildingRepository.save(building);
  this.saveAllJdbc(apartments);
}

private saveAllJdbc(List<Apartment> apartments) {
  String insertQuery = "...";
  jdbcTemplate.batchUpdate(
    insertQuery,
    apartments,
    100,
    (ps, apartment) -> // set ps values
  );
}

With the repository define as BuildingRepository extends CrudRepository<Building, UUID>, which means the save method is transactional.

Today my issue is that saveAllJdbc triggers the foreign key constraint, saying the referred building does not exist. Which means it is not aware of the current transaction.

I made it work by either using only Spring CrudRepository methods, or only JdbcTemplate methods, in both cases, the transactions were handled as defined in the documentation.

Are Spring Repository default implementation and JdbcTemplate methods supposed to share the transaction context? Or is it a known limitation?

答案1

得分: 1

这与交易无关,而与JPA的工作方式有关。

当您告诉JPA保存数据时,它不会立即执行。或者至少有选择不这样做的选项。相反,它只会保持对数据的引用,并最终保存它。"最终"通常意味着在事务结束时。

另一方面,JdbcTemplate不会执行任何花哨的操作,只会执行SQL语句。

正如Oliver Drotbohm所写,您可以通过使用JpaRepository.saveAndFlush()而不是save()来触发刷新事件来解决这个问题。

英文:

This has nothing to do with transactions and everything with how JPA works.

When you tell JPA to save data it doesn't do that.
Or at least it has the option to not do that.
Instead it will just keep a reference to the data and will eventually save it.
Eventually typically means at the end of a transaction.

JdbcTemplate on the other hand does nothing fancy and will just execute the SQL statement.

As Oliver Drotbohm wrote, you can solve this problem by triggering a flush event by using JpaRepository.saveAndFlush() instead of save().

huangapple
  • 本文由 发表于 2023年6月29日 09:41:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577585.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定