H2数据库执行INSERT INTO复合主键表失败

问题描述 投票:0回答:1

我正在使用 spring boot 3.1.2 和 maven 构建 REST java 应用程序。我的想法是在生产中使用 MySQL 数据库,并在测试时切换到内存 H2 数据库。我已通过创建在测试时覆盖数据源参数的 application-test.properties 文件,在我的 application.properties 文件中成功配置了 H2。我指定了我的 schema.sqldata.sql 文件来在测试开始时创建和填充我的 H2 数据库:

应用程序属性

spring.datasource.url=jdbc:mysql://localhost/my_db
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.auto-commit=false
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=none

应用程序测试.properties

spring.datasource.url=jdbc:h2:mem:my_db;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driver-class-name=org.h2.Driver
spring.h2.console.enabled=true

spring.sql.init.mode=ALWAYS
spring.sql.init.schema-locations=classpath:/database/schema.sql
spring.sql.init.data-locations=classpath:/database/data.sql

schema.sql

CREATE TABLE media (
  id bigint unsigned NOT NULL AUTO_INCREMENT,
  title varchar(300) NOT NULL,
  release_date date NOT NULL,
  cover_image varchar(500) DEFAULT NULL,
  description varchar(500) NOT NULL,
  audience_rating int NOT NULL,
  critic_rating int DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT rating_domain CHECK (((audience_rating >= 0) and (audience_rating <= 100)))
) AUTO_INCREMENT=1;

CREATE TABLE person (
  id bigint unsigned NOT NULL AUTO_INCREMENT,
  first_name varchar(100) NOT NULL,
  last_name varchar(100) NOT NULL,
  gender char(1) NOT NULL,
  profile_photo varchar(500) DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT const_person_gender CHECK ((gender in ('M','F','O')))
) AUTO_INCREMENT=1;

CREATE TABLE actor (
  person_id bigint unsigned NOT NULL,
  is_star tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (person_id),
  CONSTRAINT actor_ibfk_1 FOREIGN KEY (person_id) REFERENCES person (id) ON DELETE CASCADE ON UPDATE CASCADE
);

CREATE TABLE acting (
  media_id bigint unsigned NOT NULL,
  actor_id bigint unsigned NOT NULL,
  is_starring tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (media_id,actor_id),
  CONSTRAINT acting_ibfk_1 FOREIGN KEY (media_id) REFERENCES media (id) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT acting_ibfk_2 FOREIGN KEY (actor_id) REFERENCES actor (person_id) ON DELETE CASCADE ON UPDATE CASCADE
);

CREATE TABLE acting_role (
  acting_media_id bigint unsigned NOT NULL,
  acting_actor_id bigint unsigned NOT NULL,
  id bigint unsigned NOT NULL,
  name varchar(300) NOT NULL,
  PRIMARY KEY (acting_media_id,acting_actor_id,id),
  CONSTRAINT acting_role_ibfk_1 FOREIGN KEY (acting_media_id) REFERENCES acting (media_id) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT acting_role_ibfk_2 FOREIGN KEY (acting_actor_id) REFERENCES acting (actor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

尝试填充包含复合主键的代理表时,我的 data.sql 文件中出现了问题:

INSERT INTO acting(media_id,actor_id,is_starring) VALUES (1,2,1),(1,3,1);

插入mediapersonactor工作正常,只有在插入acting后才会抛出异常:

org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "public.acting_role_ibfk_1_INDEX_A ON public.acting(media_id NULLS FIRST) VALUES ( /* 1 */ CAST(1 AS BIGINT) )

我猜测这是因为 H2 无法识别 acting 表中的复合主键,而是将它们视为双主键,并且只看到我插入了相同的 media_id 两次,从而引发异常。或者可能是因为我先在 acting_role 表之前在 acting 表中插入值,该表有一个引用 acting 表的外键,所以它会抛出异常,因为我尚未在 acting_role 中插入值表,此时其值为 NULL,尽管它不应该这样做。

老实说我在这里很迷路。我尝试通过互联网和人工智能寻找答案,但似乎找不到答案。

java sql spring-boot h2
1个回答
0
投票

这不是关于如何使组合键在 H2 中工作的答案,而是在两个数据库中完成工作系统的不同方法......

30多年前,当我上“数据库学校”时,我被教导主键应该是不透明的——也就是说,没有“意义”。

这通常意味着不使用复合主键,因为如果键确实不透明,为什么需要多个?

因此,保留 media_id 和 actor_id 列,并对它们施加唯一约束,但不要将它们用作主键 -而是添加一个自动递增主键列。

© www.soinside.com 2019 - 2024. All rights reserved.