Here's an MRE:
package com.example.h2_demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DataJpaTest
@ActiveProfiles("test")
@Sql(
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
scripts = {"/create_user_table.sql", "/insert_user.sql"}
)
public class H2DemoApplicationTest {
private final UserRepository userRepository;
@Autowired
public H2DemoApplicationTest(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Test
void testNothing() {
}
@Test
void getUsers() {
List<User> users = userRepository.findAll();
assertThat(users).asList().hasSize(1);
User actualUser = users.get(0);
User expectedUser = expectedUser();
assertThat(actualUser.getId()).isEqualTo(expectedUser.getId());
assertThat(actualUser.getName()).isEqualTo(expectedUser.getName());
assertThat(actualUser.getLastName()).isEqualTo(expectedUser.getLastName());
}
private User expectedUser() {
User expectedUser = new User();
expectedUser.setId(1L);
expectedUser.setName("John");
expectedUser.setLastName("Doe");
return expectedUser;
}
}
package com.example.h2_demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class H2DemoApplication {
public static void main(String[] args) {
SpringApplication.run(H2DemoApplication.class, args);
}
}
package com.example.h2_demo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
package com.example.h2_demo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "users")
@Setter
@Getter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "last_name")
private String lastName;
}
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL,
last_name VARCHAR(50)
);
INSERT INTO users
VALUES (1, 'John', 'Doe');
# application-test.properties
# show SQL executed by Hibernate
spring.jpa.properties.hibernate.show_sql=true
# show meta comments in Hibernate statements (as specified by org.springframework.data.jpa.repository.Meta annotations)
spring.jpa.properties.hibernate.use_sql_comments=true
# to enable line breaks and indentation in logged queries executed by Hibernate
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type=trace
logging.level.org.springframework.jdbc.core=TRACE
# to see what @Sql scripts are executed
logging.level.org.springframework.test.context.jdbc=DEBUG
# to see what @Sql statements are executed
logging.level.org.springframework.jdbc.datasource.init=DEBUG
Result:
org.opentest4j.AssertionFailedError:
expected: "John"
but was: "Doe"
Expected :"John"
Actual :"Doe"
From the logs:
Hibernate:
drop table if exists users cascade
Hibernate:
create table users (
id bigint generated by default as identity,
last_name varchar(255),
name varchar(255),
primary key (id)
)
See? Hibernate messed up the order of the columns. I can, of course, disable that ddl-auto
(or specify columns in the DML script), but I'm curious why Hibernate dropped the ball with such a simple task. Never seen anything like that. Does Hibernate guarantee that table columns would be created in exactly the same order as the fields in a corresponding entity? If not, why not? It's beyond my comprehension completely
It's not strikingly obvious from the official user guide, but no, Hibernate doesn't guarantee that
If the hibernate.hbm2ddl.auto configuration is set to create, Hibernate is going to generate the following database schema:
Example 323. Auto-generated database schema
create table Customer ( id integer not null, accountsPayableXrefId binary, image blob, name varchar(255), primary key (id) )
Later in the guide...
Example 335. @LazyGroup example
@Entity public class Customer { @Id private Integer id; private String name; @Basic(fetch = FetchType.LAZY) private UUID accountsPayableXrefId; @Lob @Basic(fetch = FetchType.LAZY) @LazyGroup("lobs") private Blob image; //Getters and setters are omitted for brevity }
Notice the order. The mismatch kind of implies that Hibernate creates table columns as it sees fit