我在Spring中有一个领域对象,我正在使用JpaRepository.save方法保存它,并使用Postgres的Sequence生成器自动生成id。
@SequenceGenerator(initialValue = 1, name = "device_metric_gen", sequenceName = "device_metric_seq")
public class DeviceMetric extends BaseTimeModel {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "device_metric_gen")
@Column(nullable = false, updatable = false)
private Long id;
///// extra fields
我的使用场景需要执行一个upsert
而不是普通的save
操作(我知道如果存在id时会进行更新)。我想在现有行的三列组合(假设为复合唯一键)存在时更新该行,否则创建一个新行。
这类似于这个。INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET email = EXCLUDED.email || ';' || customers.email;
我可以想到在Spring-data中实现相同效果的一种方法是:
- 在服务层编写自定义保存操作
- 对三列进行get操作,如果存在行,则
- 将相同的id设置为当前对象并执行repository.save操作
- 如果不存在行,则执行普通的repository.save操作
上述方法的问题在于每次插入都会执行select和save,这样就需要两个数据库调用,而使用Postgres“插入冲突”功能只需一个数据库调用即可实现相同的效果。 有没有关于如何在Spring Data中实现此功能的提示?
一种方法是编写本地查询"insert into values (all fields here)"。但涉及到的对象有大约25个字段,因此我正在寻找另一种更好的方法来实现相同的效果。
INSERT ON CONFLICT
。我想找到一种更清晰的方法来做这件事,如果 JPA 支持的话,那就更好了。最终,我选择了本地 SQL,但我不认为它是一个 hack。回想起来,我同意你的看法,通过负载测试比较两种方法会很有趣,然后如果性能提升不显著,可能会更喜欢可读性更好的代码。 - abstractKarshit