Java 仅将唯一的按属性记录保存到数据库的良好做法

Java 仅将唯一的按属性记录保存到数据库的良好做法,java,spring,database,jpa,kotlin,Java,Spring,Database,Jpa,Kotlin,我想知道以下情况下的良好做法: @Entity @Table(name = "word") class WordEntity(uuid: UUID? = null, @Column(nullable = false, unique = true) val name: String ) : BaseEntity(uuid) 如果我有这个实体的一个Iterable,并且想调用saveAll方法将它持久化到数据库中,那么可以抛出一个ConstraintViolat

我想知道以下情况下的良好做法:

@Entity
@Table(name = "word")
class WordEntity(uuid: UUID? = null,
                 @Column(nullable = false, unique = true) val name: String
) : BaseEntity(uuid) 
如果我有这个实体的一个Iterable,并且想调用saveAll方法将它持久化到数据库中,那么可以抛出一个ConstraintViolationException

因此,我的目标是只向数据库中添加唯一的记录。我可以循环并执行以下操作:

fun saveAll(words: List<WordRequest>): List<WordDTO> {

        ...

        for (wordEntity in wordEntities) {
            try {
                result.add(wordRepository.save(wordEntity))
            } catch (e: RuntimeException) { }
        }

        ...
    }
或者我可以在每个循环上使用findByName来检查它是否存在

所以我的问题是我应该选择哪个选项,有没有更好的方法来处理这个问题?

您有两个选项:

有些数据库支持INSERT IF EXIST语法。这正是你所需要的。但这意味着您需要编写一个本机SQL。 如果您想坚持使用ORM,您必须打开一个新会话,并为每个记录启动新事务。因为如果抛出异常,您不能继续依赖同一个会话EntityManager,那么该行为是未记录的。
检查记录是否已存在可能会减少失败的插入次数。您可以在1 SELECT using in语句中执行此操作,但这不能保证任何事情—SELECT和INSERT之间有一段时间。另一个事务可以插入中间。除非您使用可序列化隔离级别

谢谢你的回答。我尝试了第一个选项,使用原生查询@query value=INSERT插入单词uuid,冲突名称上的名称值?1、?2不做任何事情;,nativeQuery=true,但它引发GenericJDBCException:无法提取结果集。因为如果使用Spring数据,它无法插入ITI,所以您还需要添加@Modifying for INSERTs/updates来解决问题,谢谢。您知道在添加修改注释时可以将插入的行作为实体返回吗?因为您使用的是UUID,所以您没有getGeneratedKeys选项。因此,这可能是不可能的,请查看您的DB是否支持返回语法:。您必须尝试使用SpringData,例如remove@Modifying,但我猜您必须在纯JDBC中进行此操作。