当前位置: 首页 > 知识库问答 >
问题:

通过数据库中的唯一约束进行重复检查不工作

彭烨熠
2023-03-14

我有一个Spring Boot服务,它应该将事务中两种类型的多个实体持久化到Oracle DB。第一种实体类型的表是巨大的(每天300万个条目,分区…),我有一个问题,我需要对重复项做出反应。我使用一些字段来创建哈希,并且在数据库中对该字段有一个唯一的约束。我认为一个聪明的想法是一个实体一个实体地保存和刷新,并对ConstraintViolationException做出反应。根据保存第一个实体列表的结果,我需要创建第二个实体并保存它,但它会回滚所有内容。我现在的问题是,如果这种方法通常是错误的,或者可以,并且存在一些小问题?如果这通常是错误的,那么我应该如何进行重复检查(预先选择不是选项)?

下面是一些伪代码,可以让你有更好的想法

@Entity
public class Foo{

    public String uniqueHash;
    
    // couple of other properties that will be used to calculate the hash
}

@Entity
public class Bar{

    private List goodIds;
    private List badIds;
    
    public Bar(List goodIds, List badIds){
        this.goodIds = goodIds;
        this.badIds = badIds;
    }
}

@Repository
@Transactional(noRollbackFor = PersistenceException.class)
public interface FooRepository extends JpaRepository<Foo, String> {
  Foo saveAndFlush(Foo f) throws PersistenceException;
}

@Repository
@Transactional(noRollbackFor = PersistenceException.class)
public interface BarRepository extends JpaRepository<Bar, String> {
  Bar saveAndFlush(Bar b) throws PersistenceException;
}

SomeService

@Transactional(noRollbackFor = PersistenceException.class)
public void doSomething(List<Foo> foos){

    List<String> goodIds = new ArrayList();
    List<String> badIds = new ArrayList();
        
    for (Foo foo : foos) {
      try {     
        fooRepository.saveAndFlush(foo);
        goodIds.add(foo.getId());
      } catch (PersistenceException e) {
        if (e.getCause() instanceof ConstraintViolationException) {
          badIds.add(foo.getId);
        } else {
          throw e;
        }
      }
    }
    barRepository.saveAndFlush(new Bar(goodIds, badIds));
}

共有2个答案

索吕恭
2023-03-14

为此,您可以使用自定义的< code>@SQLInsert来利用Oracles MERGE语句。另请参见https://stackoverflow.com/a/64764412/412446

韩恺
2023-03-14

最后,我找到了一种方法来实现预期的行为,甚至更好的是,我能够摆脱这些“noRollBackFor”属性。我只是重组了流程,并尝试保存事务中的所有内容,如果失败,Exception被捕获在调用方法上,输入被“清理”,事务方法被再次调用(递归)。这些重复是罕见的情况(每10kFoo实例都会发生),所以从性能的角度来看,有这些后续事务是可以的。这里又是更改后的伪代码

@Entity
public class Foo{

    public String uniqueHash;
    
    // couple of other properties that will be used to calculate the hash
}

@Entity
public class Bar{

    private List goodIds;
    private List badIds;
    
    public Bar(List goodIds, List badIds){
        this.goodIds = goodIds;
        this.badIds = badIds;
    }
    
    public List getGoodIds(){
      return goodIds;
    }
    
    public List getBadIds(){
      return badIds;
    }
}

@Repository
public interface FooRepository extends JpaRepository<Foo, String> {
}

@Repository
public interface BarRepository extends JpaRepository<Bar, String> {
}

public class FooException extends RuntimeException {

  private final Foo foo;

  public FooException(String message, Foo foo) {
    super(message);
    this.foo = foo;
  }
  
  public getFoo(){
  return foo;
  }
}

SomeService

public void doSomething(List<Foo> foos, Bar bar){
        try{
        doSomethingTransactional(foos,bar);
        }
        catch (FooException e) {           
          bar.getBadIds().add(e.getFoo().getId());
          foos.remove(foo);
          doSomething(foos, bar);
        }
}


@Transactional
public void doSomethingTransactional(List<Foo> foos, Bar bar){
        
    for (Foo foo : foos) {
      try {     
        fooRepository.saveAndFlush(foo);
        bar.getGoodIds.add(foo.getId());
      } catch(DataAccessException e) {
        if (e.getCause() instanceof ConstraintViolationException 
        && ((ConstraintViolationException) e.getCause()).getConstraintName().contains("Some DB Message")) {
          throw new FooException("Foo already exists", foo);
        } else {
          throw e;
        }
      }
    }
    barRepository.saveAndFlush(bar);
}
 类似资料:
  • 问题内容: 我正在JPA中对userid列强制执行唯一性约束检查,这是对user表中的所有记录强制执行的。 我的要求是,特定组织内的用户ID必须唯一,而不是在所有组织中都唯一。 如何执行此类检查? 问题答案: 您可以为唯一约束指定多个字段,请尝试: 通过这样做,您的约束条件将检查userid和Organizationid的组合是否唯一。 最好的祝福,费边

  • 我遇到一个情况,需要根据另一个列值对一个列[属性]强制执行唯一约束。 例如,我有一个像table(ID,EID,Name,ISDeleted)这样的表 ISDeleted只能有一个值null或'y'(active或deleted),并且我想在EID上创建一个唯一的约束,仅当ISDeleted=null时才创建ISDeleted,因为我不关心是否有多个具有相同ID的已删除记录。请注意,EID可以为空

  • 我有一个spring项目,想在数据库中强制一个字段的唯一性,并将错误消息返回给UI。 我已经阅读了这个SO答案,它是有意义的,所以@Col的(唯一=真)使表上的约束,但不强制它。 因此,问题变成了如何创建一个@Unique注释,该注释与数据库进行检查,并在POST处理程序上向BindingResult返回错误消息。 一个例子会很棒。 更新 我尝试了以下方法来制作自定义验证器: 对象(请注意,我添加

  • 问题内容: 我想在我的MySQL表上添加一个唯一性约束。该表包含四列: 此约束必须检查对于new行,new和都未包含在或中。 例子 : 有没有办法定义这样的约束? 问题答案: 您可以通过触发器来做到这一点 注意: 由于您使用的MySQL版本缺少技巧,因此当找到具有相同地址的行时,违反对其中一列的约束。 这是 SQLFiddle 演示。取消注释最后一个插入语句之一,然后单击确定。这些插入不会成功。

  • 我有以下JPA实体 这是我检查唯一约束的测试,插入具有相同电子邮件的另一个用户。

  • 我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。 当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。 当这种违反发生时,我从MySQL数据库中得到的异常是: 有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。 选项1