Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DDL generations differs between Spring Boot 3.0.x and 3.1.x when using UUID #3087

Closed
SeaLife opened this issue Jul 27, 2023 · 6 comments
Closed
Assignees
Labels
for: external-project For an external project and not something we can fix

Comments

@SeaLife
Copy link

SeaLife commented Jul 27, 2023

Hey,

I've recently updated my application from Spring Boot 3.0.x to 3.1.1 (and today to 3.1.2) and encountered the following issue:

When generating a DDL using the following EntityClass:

@Entity
@Getter
@Setter
public class Appointment {
    @Id
    @JdbcTypeCode(SqlTypes.VARCHAR)
    private UUID   id;
    private String title;
    @Column(columnDefinition = "TEXT")
    private String description;
    private String category;

    @Enumerated(EnumType.STRING)
    private AccountType accountType;

    private boolean open = false;

    private Integer userLimit = null;

    private int trustLevel = 0;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private ZonedDateTime start;
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private ZonedDateTime end;

    private Boolean timed = true;
    private String  color = "primary";

    @ManyToOne
    private User createdBy;

    @ManyToMany
    private List<User> registeredUsers = new ArrayList<>();
}

The id-Column is generated with a VARCHAR(255) on Spring Boot 3.0.x but with a id-Column of VARCHAR(36) on Spring Boot 3.1.x

I tried using @Column(length = 255) to force a generation of VARCHAR(255) but the Column-Annotation was simply ignored.

Configuration

spring:
  datasource:
    url: 'jdbc:mariadb://db.xxxxx.de:xxxx/xxxx'
    username: 'xxxxx'
    password: 'xxxxx'
  jpa:
    generate-ddl: true
    hibernate:
      ddl-auto: update
    show-sql: true

Stacktrace

2023-07-27T13:07:03.540+02:00  WARN 43496 --- [  restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL "alter table if exists appointment modify column id  varchar(36) not null" via JDBC [(conn=3268) Cannot change column 'id': used in a foreign key constraint 'FK8dpmsvheg2i2kn33cjbi5652n' of table 's19_govnet.appointment_registered_users']

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table if exists appointment modify column id  varchar(36) not null" via JDBC [(conn=3268) Cannot change column 'id': used in a foreign key constraint 'FK8dpmsvheg2i2kn33cjbi5652n' of table 's19_govnet.appointment_registered_users']
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:92) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:574) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:514) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.migrateTable(AbstractSchemaMigrator.java:333) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:84) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:232) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:117) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:284) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:143) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at java.base/java.util.HashMap.forEach(HashMap.java:1429) ~[na:na]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:140) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:37) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:292) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:431) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1455) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) ~[spring-orm-6.0.11.jar:6.0.11]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) ~[spring-orm-6.0.11.jar:6.0.11]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-6.0.11.jar:6.0.11]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-6.0.11.jar:6.0.11]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) ~[spring-orm-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1817) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1766) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) ~[spring-context-6.0.11.jar:6.0.11]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-6.0.11.jar:6.0.11]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[spring-context-6.0.11.jar:6.0.11]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.1.2.jar:3.1.2]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-3.1.2.jar:3.1.2]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) ~[spring-boot-3.1.2.jar:3.1.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-3.1.2.jar:3.1.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-3.1.2.jar:3.1.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-3.1.2.jar:3.1.2]
	at de.alteravitarp.AlteraVitaServiceApplication.main(AlteraVitaServiceApplication.java:28) ~[classes/:na]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.1.2.jar:3.1.2]
Caused by: java.sql.SQLException: (conn=3268) Cannot change column 'id': used in a foreign key constraint 'FK8dpmsvheg2i2kn33cjbi5652n' of table 's19_govnet.appointment_registered_users'
	at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:299) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:370) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:134) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:872) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:811) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.client.impl.StandardClient.readResponse(StandardClient.java:730) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.client.impl.StandardClient.execute(StandardClient.java:654) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.Statement.executeInternal(Statement.java:957) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.Statement.execute(Statement.java:1083) ~[mariadb-java-client-3.1.4.jar:na]
	at org.mariadb.jdbc.Statement.execute(Statement.java:474) ~[mariadb-java-client-3.1.4.jar:na]
	at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) ~[HikariCP-5.0.1.jar:na]
	at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-5.0.1.jar:na]
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:78) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
	... 41 common frames omitted
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 27, 2023
@rishiraj88
Copy link

Try enforcing the column length by writing @column (length=255) yourself for id.

@SeaLife
Copy link
Author

SeaLife commented Jul 27, 2023

Try enforcing the column length by writing @column (length=255) yourself for id.

As i stated above, i already tried that:

I tried using @column(length = 255) to force a generation of VARCHAR(255) but the Column-Annotation was simply ignored.

@gregturn
Copy link
Contributor

Spring Data JPA 3.0.x (Boot 3.0) is on Hibernate 6.1 while Spring Data JPA 3.1+ (Boot 3.1+) is on Hibernate 6.2. Since we don't actually do any data schema creation (this is courtesy of Hibernate), it sounds like either a misconfigured Hibernate/JPA issue or a bug in Hibernate 6.2 altogether.

I'd suggest creating a reproducer based purely on Hibernate and submitting an issue with them.

To get more info, you can also add the following to your application.properties file:

logging.level.org.springframework.data.jpa=trace
logging.level.org.springframework.jdbc=debug
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.orm.jdbc.bind=trace

If you think this is actually a Spring Data issue, please provide a reproducer for the issue including a test case that demonstrates the correct behavior using the EntityManager directly.

@gregturn gregturn self-assigned this Jul 27, 2023
@gregturn gregturn added for: external-project For an external project and not something we can fix theme: hibernate 6 and removed status: waiting-for-triage An issue we've not yet triaged theme: hibernate 6 labels Jul 27, 2023
@SeaLife
Copy link
Author

SeaLife commented Jul 28, 2023

Hey, so i created a new project to verify the issue..
With Spring Boot 2.0.x i used the following class definition for UUID types:

@Getter
@Setter
@Entity
public class Entity1 {

    @Id
    @Type(type = "uuid-char")
    private UUID id;

    private String field1;
    private String field2;
    private String field3;
}

@Getter
@Setter
@Entity
public class Entity2 {

    @Id
    @Type(type = "uuid-char")
    private UUID id;

    @ManyToOne
    private Entity1 entity1;

    private String field1;
    private String field2;
    private String field3;
}

Which results in the following SQL:

create table entity1 (id varchar(255) not null, field1 varchar(255), field2 varchar(255), field3 varchar(255), primary key (id)) engine=InnoDB;
create table entity2 (id varchar(255) not null, field1 varchar(255), field2 varchar(255), field3 varchar(255), entity1_id varchar(255), primary key (id)) engine=InnoDB;
alter table entity2 add constraint FK133qwgxc648anidh2vf15ojsr foreign key (entity1_id) references entity1 (id);

In Spring Boot 3.0.x the generated SQL with a modified Entity Class to use @JdbcTypeCode instead of @Type the following SQL will be generated, which is the same for 3.1.x:

create table entity1 (id varchar(36) not null, field1 varchar(255), field2 varchar(255), field3 varchar(255), primary key (id)) engine=InnoDB;
create table entity2 (id varchar(36) not null, field1 varchar(255), field2 varchar(255), field3 varchar(255), entity1_id varchar(36), primary key (id)) engine=InnoDB;
alter table entity2 add constraint FK133qwgxc648anidh2vf15ojsr foreign key (entity1_id) references entity1 (id);

Spring Boot 3.0.x does not alter the tables if the type length differs from the entity definition but Spring Boot 3.1.x verifies the length and tries to change them (probably due to some changes in Hibernate?)

@gregturn
Copy link
Contributor

gregturn commented Aug 1, 2023

I'm going to close this issue. If you feel there is a Spring Data JPA issue here, feel free to come back and provide additional details.

@gregturn gregturn closed this as not planned Won't fix, can't repro, duplicate, stale Aug 1, 2023
@SeaLife
Copy link
Author

SeaLife commented Aug 8, 2023

Just to let you guys know aswell, i opened up a question thread in the hibernate forum (https://discourse.hibernate.org/t/ddl-generations-differs-between-spring-boot-2-x-and-3-x-when-using-uuid) and they suggested to drop all foreign keys and alter the table afterwards which worked just fine in my usecase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

4 participants