[英]Is there a way to save an @Entity with pre-defined @EmbeddedId value using Spring Data's CrudRepository#save() method?
I'm creating a new service with the goal of consuming Kafka events in an idempotent manner and storing the data into a new PostgreSQL database. 我正在创建一个新服务,目的是以幂等方式使用Kafka事件并将数据存储到新的PostgreSQL数据库中。
The event will provide data which will be used in the composite key: 该事件将提供将在复合键中使用的数据:
@Embeddable
public class MyCompositeKey implements Serializable {
@Column(name="field1", nullable = false)
private UUID field1;
@Column(name="field2", nullable = false)
private UUID field2;
@Column(name="field3", nullable = false)
private UUID field3;
... boilerplate Constructors/getters ...
And the Entity will be referencing it via @EmbeddedId
: 实体将通过
@EmbeddedId
引用它:
@Entity
@Table
public class MyEntity implements Serializable {
@EmbeddedId private MyCompositeKey myCompositeKey;
... Columns/Constructors/getters ...
When an event is consumed, I want to let spring-data-jpa
be smart enough to know whether we are replacing data from an existing MyEntity, or creating a new row. 当一个事件被消耗时,我想让
spring-data-jpa
足够聪明,知道我们是在替换现有MyEntity中的数据,还是创建一个新行。
The logic was deemed safe enough to use the CrudRepository#save
method before researching the expectation of the logic within that method: 在研究该方法中逻辑的期望之前,逻辑被认为足够安全,可以使用
CrudRepository#save
方法:
@Transactional
public <S extends T> S save(S entity) {
if (this.entityInformation.isNew(entity)) {
this.em.persist(entity);
return entity;
} else {
return this.em.merge(entity);
}
}
I've gotten to the point where the transactions appear to be completed, but no records are persisted to the table. 我已经达到了交易似乎已完成的程度,但没有记录持久存在于表中。
I've confirmed via debugging that the call to #save
is branching into the return this.em.merge(entity)
logic referenced above. 我已通过调试确认对
#save
的调用是分支到return this.em.merge(entity)
的return this.em.merge(entity)
逻辑。
I've only found one possibly helpful blog post[1] for a similar scenario, and am lost on where to go next after it didn't seem to resolve the issue. 我只发现了一个可能有用的博客文章[1],用于类似的场景,并且在它似乎无法解决问题之后,我会失去下一步该去的地方。
The only other option I can foresee is to manually go through a potential three-query execution: 我可以预见的唯一其他选择是手动执行潜在的三查询执行:
findById
delete
delete
save
[1] https://jivimberg.io/blog/2018/11/05/using-uuid-on-spring-data-jpa-entities/ [1] https://jivimberg.io/blog/2018/11/05/using-uuid-on-spring-data-jpa-entities/
Alright, I found the issue. 好吧,我发现了这个问题。 All of this design was working fine, it was the configuration which was missing.
所有这些设计都运行良好,缺少配置。
For some context - Spring Boot seems to configure default javax.sql.DataSource
, default javax.persistence.EntityManagerFactory
, and default org.springframework.transaction.PlatformTransactionManager
beans. 对于某些上下文 - Spring Boot似乎配置了默认的
javax.sql.DataSource
,默认的javax.persistence.EntityManagerFactory
和默认的org.springframework.transaction.PlatformTransactionManager
bean。
My context was configured with a javax.sql.DataSource
bean in order to specify a configuration prefix distinction using org.springframework.boot.context.properties.ConfigurationProperties
. 我的上下文配置了
javax.sql.DataSource
bean,以便使用org.springframework.boot.context.properties.ConfigurationProperties
指定配置前缀的区别。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"com.myservice"})
public class RepositoryConfiguration {
@Bean
@ConfigurationProperties(prefix = "myservice.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
My context did not add in replacements for the dependent javax.persistence.EntityManagerFactory
and org.springframework.transaction.PlatformTransactionManager
beans. 我的背景并没有替代因添加
javax.persistence.EntityManagerFactory
和org.springframework.transaction.PlatformTransactionManager
豆。
The fix was to add in all of the configuration. 修复是添加所有配置。 From the docs :
来自文档 :
You must create LocalContainerEntityManagerFactoryBean and not EntityManagerFactory directly, since the former also participates in exception translation mechanisms in addition to creating EntityManagerFactory.
您必须直接创建LocalContainerEntityManagerFactoryBean而不是EntityManagerFactory,因为除了创建EntityManagerFactory之外,前者还参与异常转换机制。
The resulting configuration: 结果配置:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"com.myservice"})
public class RepositoryConfiguration {
@Bean
@ConfigurationProperties(prefix = "myservice.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.myservice");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.