Javax 唯一约束行为 持久化重复行时

Posted

技术标签:

【中文标题】Javax 唯一约束行为 持久化重复行时【英文标题】:Javax Unique Contraints behavior When persisting duplicate row 【发布时间】:2017-09-20 12:55:01 【问题描述】:

假设我在 Postgresql 数据库中有一个表:

CREATE TABLE FOO (
   ID INT PRIMARY KEY      NOT NULL,
   NAME           CHAR(50) UNIQUE NOT NULL
);

在 Spring Boot 应用程序中由 hibernate 创建

我想插入以下内容:

INSERT INTO FOO (ID, NAME) VALUES (1, "BAR");
INSERT INTO FOO (ID, NAME) VALUES (2, "BAZ");
INSERT INTO FOO (ID, NAME) VALUES (3, "ZIP");

在以下类中时作为种子数据:

@Component
public class SeedDB implements CommandLineRunner 

  private final FooRepository fooRepository;

  @Autowired
  public SeedDB(FooRepository fooRepository) 
    this.fooRepository = fooRepository;
  

  @Override
  public void run(String... strings) throws Exception 
    fooRepository.save(new Foo("bar"));
    fooRepository.save(new Foo("baz"));
    fooRepository.save(new Foo("zip"));
  

所有这些只是说,只要数据库是空的,它就可以很好地工作。但如果将其设置为每次应用程序启动时运行,则唯一约束会导致以下错误:

Caused by: org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [ukjsk1parw92chjvhsj49tl7492]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "ukjsk1parw92chjvhsj49tl7492"
Detail: Key (name)=(bar) already exists.

我想这是有道理的。我想弄清楚的是,是否有一种方法,无需将每一行包装在 if/else 或 try/catch 块中,就可以尝试插入而不考虑结果?

问题是我不能使用 create-drop hibernate 方法,因为架构中还有其他表不能丢失。

【问题讨论】:

我想弄清楚的是,如果有办法,不用将每一行都包装在 if/else 或 try/catch 块中这样做有什么问题?但无论如何,有更好的方法来做到这一点 - 见***.com/questions/22269307/inserting-initial-data-jpa @ScaryWombat,这是很好的信息,但我不能删除当前的数据库。还有其他不能丢失的表。您链接的帖子提到了策略。有没有插入数据但不删除表的更新策略? 我不是要你放弃任何东西 - 阅读接受的答案。同样正如我所问,try-catch 有什么问题? 【参考方案1】:

您可以在这里使用try catch 块,但我认为在unique 字段的情况下,我们应该每次在数据库中检查(字段是否存在),然后才能持久化我们的实体,这样它就会返回它的保证,而且我认为这是更好的方法,因为如果我们将处理 ConstraintViolationException(Implementation of JDBCException indicating that the requested DML operation resulted in a violation of a defined integrity constraint.),则在尝试捕获的情况下,any case of DML operation resulted in a violation 可能会发生此异常,因此最好确保我们提交是唯一的,我们需要在持久化之前检查它,如果存在实体我们可以为用户或日志显示用户友好的消息。

在你的情况下,代码会喜欢:

if(fooRepository.countByFiledName("bar")==0) 
 fooRepository.save(new Foo("bar"));

【讨论】:

以上是关于Javax 唯一约束行为 持久化重复行时的主要内容,如果未能解决你的问题,请参考以下文章

当使用违反唯一约束的实体调用 persist() 时没有持久性异常

mysql唯一约束

IntegrityError:重复键值违反唯一约束

mysql中多列的唯一约束[重复]

检查重复记录 VS 尝试/捕获唯一键约束

如何在 SSMS 2012 中创建唯一约束 [重复]