Spring Data JPA主键违规约束不起作用

Posted

技术标签:

【中文标题】Spring Data JPA主键违规约束不起作用【英文标题】:Spring Data JPA Primary Key Violation Constraint Not Working 【发布时间】:2021-01-31 06:28:21 【问题描述】:

代码和配置:

使用的数据库 - 内存数据库中的 H2

用户实体:

@Entity
@Table(name = "users")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable 

    /**
     * 
     */
    private static final long serialVersionUID = 455202739064202185L;
    
    @Id // please note is not auto generated but manually generated 
    @Column(name = "id",unique=true)
    @NotNull
    private long id;
    
    @Column(name = "firstName")
    @NotEmpty(message = "First name is required")
    private String firstName;
    
    @Column(name = "lastName")
    @NotEmpty(message = "Last name is required")
    private String lastName;    
    
    @Column(name = "email")
    @NotEmpty(message = "Email is required")
    @Email(message="Email Must be well formed")
    private String email;
    
    

用户存储库:

public interface UserJpaRepository extends JpaRepository<User, Long> 

    

UserServiceImpl :

this.userJpaRepository.saveAll(users);

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.exostar</groupId>
    <artifactId>FileUpload</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>FileUpload</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-csv</artifactId>
           <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>   
    </dependencies>
</project>

问题:

根据用户实体类,手动生成@Id。 (我有一个 CSV 文件,其中包含在用户实体中读取的 Id 字段) 所以 Id 不是自动生成的

每当我调用 this.userJpaRepository.saveAll(users) 时,即使有一个带有 Id 的 User entity 已经存在,User entity 也会被覆盖。 也就是说,具有相同实体的Id 会被新数据覆盖。

它必须抛出 - Unique index or primary key violation error

但是,当我尝试在 H2 数据库中手动插入 重复条目 时,它会引发异常 - Unique index or primary key violation

我还尝试将unique=true 添加到用户实体中的 Id 字段,但它不起作用 有人可以帮忙解决这个问题吗?

【问题讨论】:

这是因为save() 会在 id 存在时更新。您必须手动检查是否存在 id 【参考方案1】:

事实证明,您看到的行为是因为在 save() 实现中调用了 em.merge(...)。以下是实际发生的情况:

@Transactional
@Override
public <S extends T> S save(S entity) 

    Assert.notNull(entity, "Entity must not be null.");

    if (entityInformation.isNew(entity)) 
        em.persist(entity);
        return entity;
     else 
        return em.merge(entity); // Update if the entity is not new
    

这是来自SimpleJpaRepository 实现的示例代码。您可以使用自己的查询方法来更新现有查询,如下所示:

@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

【讨论】:

以上是关于Spring Data JPA主键违规约束不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Spring -data-jpa ,存储库类不起作用

Spring Data JPA 查询不起作用,列不存在

Spring Data JPA - 查询日期减去 2 天不起作用

Spring Data JPA自定义查询限制功能不起作用[重复]

从父类更新日期字段在 Spring Data Jpa 中不起作用

使用 Spring Boot 和 Spring Data JPA 批量插入不起作用