如何防止批量插入时生成的值重复

时间:2017-03-11 22:56:37

标签: java sql spring spring-data-jpa unique

我的group类有一个令牌属性,我的Java代码用它来验证是否应该允许操作,具体取决于谁试图调用它。我有用于生成字母数字键并在组构造函数中分配令牌的代码。例如

public Group(){
    super();
    this.token = Crypt.generate(30); // length of key
}

这工作正常,我的数据库现在很小,但是,我认为生成的密钥有可能已经存在。在这种情况下,当我尝试将数据插入数据库时​​,我将收到org.springframework.dao.DataIntegrityViolationException。我讨论了在try / catch中包装每个insert语句然后再次尝试,但我还需要检查本可以成功保存的记录,因为我现在通常在批处理中插入Group表。

List<Group> groups = new ArrayList<>();
groups.add(new Group("grp1");
groups.add(new Group("grp2");
groups.add(new Group("grp3");

try {
   groupRepository.save(groups);

} catch (DataIntegrityViolationException e){

   List<Group> secondAttemptGroups = new ArrayList<>();

   for(Group g : groups){

       Group insertedGroup = groupRepository.findByName(g.getName());

       if(insertedGroup == null){

           secondAttempGroups.add(new Group(g.getName());   
       }
   }
   if(!(secondAttempGroups.isEmpty()){

      try {

          group.repository.save(secondAttempGroups);

      } catch(DataIntegrityViolationException e2){
          // ...
      }
   }
}

必须有更好的方法来防止这种情况发生。

1 个答案:

答案 0 :(得分:0)

在仔细考虑了这个问题后,我认为我可以使用Spring JPA验证令牌,而无需将整个数据库放入我的代码中。这就是我想出来的。

public static List<Group> validateTokens(List<Group> groups, int iterations){

    LOGGER.info("Validating Tokens: Iteration #" + iterations); 

    boolean dirtyToken = false;

    // Validate that the groups provided don't contain duplicate tokens. 

    Set<String> tokenSet = new HashSet<>();

    for(Group g1 : groups){
        tokenSet.add(g1.getToken());
    }
    if(tokenSet.size() != groups.size()){
        dirtyToken = true;

        for(Group g2 : groups){
            g2.setToken(Crypt.generate(TOKEN_LENGTH));
        }
    }

    // Validate that the groups provided don't contain tokens that are already present in the database.

    for(Group g3 : groups){
        Group databaseGroup = groupRepository.findByToken(g3.getToken());

        if(databaseGroup != null){
            dirtyToken = true;
            g3.setToken(Crypt.generate(TOKEN_LENGTH));
        }
    }
    if(dirtyToken && iterations-- > 0){
        return validateTokens(groups, iterations);
    }
    else if(dirtyToken && iterations < 1){
        LOGGER.warn("Tokens could not be validated and Unique Constraint Violtation will be thrown. " + 
                    "Perhaps it's time to increase the token length from " + TOKEN_LENGTH + ".");
        return groups;
    }
    else {
        return groups;
    }

上面的递归方法有效。 @Robert我没有考虑数据库生成的值,但在开发过程中我将仅使用h2作为我的数据库。这种方法是否仍然可行,也许更容易?