提问人:Kodigas 提问时间:11/15/2023 更新时间:11/15/2023 访问量:48
Hibernate 在创建表时交换列。它到底为什么要这样做?
Hibernate swaps columns around when creating a table. Why on earth does it do it?
问:
下面是一个 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
结果:
org.opentest4j.AssertionFailedError:
expected: "John"
but was: "Doe"
Expected :"John"
Actual :"Doe"
从日志中:
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)
)
看?Hibernate 打乱了列的顺序。当然,我可以禁用它(或在 DML 脚本中指定列),但我很好奇为什么 Hibernate 在如此简单的任务中丢球。从未见过这样的事情。Hibernate 是否保证表列的创建顺序与相应实体中的字段完全相同?如果不是,为什么不呢?这完全超出了我的理解ddl-auto
答:
0赞
Kodigas
11/15/2023
#1
从官方用户指南来看,这一点并不明显,但不,Hibernate 并不能保证这一点
如果 hibernate.hbm2ddl.auto 配置设置为 create,Hibernate 将生成以下数据库模式:
例 323.自动生成的数据库架构
create table Customer ( id integer not null, accountsPayableXrefId binary, image blob, name varchar(255), primary key (id) )
在指南的后面...
例 335.@LazyGroup示例
@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 }
注意顺序。这种不匹配意味着 Hibernate 会按照它认为合适的方式创建表列
评论
0赞
Chris
11/15/2023
除非它或 JPA 规范规定在 DDL 生成中对列有顺序 - 否则没有任何保证。顺序不应该重要,也不应该被假定为受属性定位的控制,这就是为什么 JPA 提供程序显式列出他们正在选择、插入和更新的列的原因。
评论
@Sql
@BeforeEach
AccountRepository
CreditRepository
CreditOrderRepository
ProductRepository
CardRepositoryTest
EveryRepositoryTest