java 尝试在H2表中插入实体时发生DataIntegrityViolationException

b1uwtaje  于 2023-02-11  发布在  Java
关注(0)|答案(2)|浏览(154)

使用Java 17.0.2和Spring Bootstrap 3.0.2(与Spring Bootstrap 2.7.x存在相同问题)
(这里有一个示例项目:https://github.com/fistons/issue-spring-data-test
我有一个实体及其存储库:

@Entity
@Table(name = "customers")
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Customer {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "name", unique = true, nullable = false, length = 255)
  private String name;

  @Column(name = "region")
  @Enumerated(EnumType.STRING)
  private Region region;

  public enum Region {
    US,
    EU
  }
}
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {}

我创建了一个简单的服务来插入一个新实体

@Service
public class CustomerService {

  private final CustomerRepository customerRepository;

  public CustomerService(CustomerRepository customerRepository) {
    this.customerRepository = customerRepository;
  }

  @Transactional
  public Customer createCustomer(String name, Customer.Region region) {

    Customer customer = new Customer();
    customer.setName(name);
    customer.setRegion(region);

    return customerRepository.save(customer);
  }
}

我创建了此测试(使用内存H2数据库运行):

@SpringBootTest
@Transactional
class CustomerServiceTest {

  @Autowired
  private CustomerService customerService;

  @Test
  public void test_createCustomer() {
    Customer createdCustomer = customerService.createCustomer("The Crusher", Customer.Region.EU);

    Assertions.assertEquals(4, createdCustomer.getId(), "Id should match");
    Assertions.assertEquals("The Crusher", createdCustomer.getName(), "Name should match");
    Assertions.assertEquals(Customer.Region.EU, createdCustomer.getRegion(), "Region should match");
  }
}

使用此data.sql固定装置:

INSERT INTO customers (id, name, region) VALUES (1, 'Dr. Carmack', 'EU'), (2, 'Pinky', 'EU'), (3, 'Revenant', 'EU');

我在测试应用程序中显式设置了spring.jpa.defer-datasource-initialization: true。yml
当我运行这个测试时,我遇到了一个异常,我不知道为什么:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.CUSTOMERS(ID) ( /* key:1 */ 1, 'Dr. Carmack', 'EU')"; SQL statement:
insert into customers (id, name, region) values (default, ?, ?) [23505-214]]

当我查看测试日志时,我可以看到hib使用以下请求创建表:

create table customers (
       id integer generated by default as identity,
        name varchar(255) not null,
        region varchar(255),
        primary key (id)
    )

看起来当服务中有一个插入时,ID应该是4,因为我的fixture中已经有3个插入行。
为什么它试图分配id 1?我错过了什么吗?

fwzugrvs

fwzugrvs1#

层代类型.标识

此GenerationType指示持久性提供程序必须使用数据库标识列为实体分配主键。IDENTITY列通常用于SQL Server中。此特殊类型列由表本身在内部填充,而不使用单独的序列。如果基础数据库不支持IDENTITY列或某些类似的变量,则持久性提供程序可以选择适当的替代策略。在本例中,我们使用的是不支持IDENTITY列的H2数据库。
您应该考虑将ID持久性类型更改为GenerationType.AUTO或其他类型

suzh9iv8

suzh9iv82#

Id的生成方式取决于框架和数据库。通常由Sequence完成,而Sequence不知道您的插入,所以它从1开始。您可以注解Customer类,使用哪个序列,并使用此序列在data.sql中创建以避免此错误。

相关问题