abs*_*hit 8 postgresql spring spring-data-jpa spring-boot
我在 Spring 中有一个域对象,我使用 JpaRepository.save 方法保存它并使用 Postgres 的序列生成器自动生成 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
Run Code Online (Sandbox Code Playgroud)
我的用例需要做一个upsert而不是正常的save操作(我知道如果 id 存在就会更新)。如果存在三列的组合(假设复合唯一),我想更新现有行,否则创建新行。这与此类似:
INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET email = EXCLUDED.email || ';' || customers.email;
Run Code Online (Sandbox Code Playgroud)
我能想到的在 Spring-data 中实现相同的一种方法是:
上述方法的问题在于,每次insert都执行 aselect和 thensave进行两次数据库调用,而 postgresinsert on conflict功能只需一次 db 调用即可实现相同的效果。关于如何在 Spring Data 中实现这一点的任何指示?
一种方法是编写本机查询insert into values (all fields here)。有问题的对象有大约 25 个字段,所以我正在寻找另一种更好的方法来实现相同的目标。
小智 0
我建议使用命名查询来根据候选键获取行。如果存在一行,则更新它,否则创建一个新行。这两个操作都可以使用 save 方法来完成。
@NamedQuery(name="getCustomerByNameAndEmail", query="select a from Customers a where a.name = :name and a.email = :email");
Run Code Online (Sandbox Code Playgroud)
您还可以在实体上使用 @UniqueColumns() 注释,以确保这些列在分组在一起时始终保持唯一性。
Optional<Customers> customer = customerRepo.getCustomersByNameAndEmail(name, email);
Run Code Online (Sandbox Code Playgroud)
在您的存储库中实现上述方法。它所要做的就是调用查询并将名称和电子邮件作为参数传递。如果不存在任何行,请确保返回Optional.empty()。
Customers c;
if (customer.isPresent()) {
c = customer.get();
c.setEmail("newemail@gmail.com");
c.setPhone("9420420420");
customerRepo.save(c);
} else {
c = new Customer(0, "name", "email", "5451515478");
customerRepo.save(c);
}
Run Code Online (Sandbox Code Playgroud)
将 ID 传递为 0,JPA 将插入一个新行,其中包含根据序列生成器生成的 ID。
尽管我从不建议使用数字作为 ID,但如果可能的话,使用随机生成的 UUID 作为主键,它将保证唯一性并避免序列生成器可能出现的任何意外行为。
| 归档时间: |
|
| 查看次数: |
2721 次 |
| 最近记录: |