在实际应用中,遇到数据库表中字段名称含大小写的情况(如taskId,历史遗留问题,不能修改数据库),在使用Hibernate进行ORM时,遇到找不到字段或数据库新生成字段问题。本篇以PostgreSQL 9.6数据库和Hibernate 5.2.12.Final为例,探讨Hibernate5中ORM时表字段大小写敏感问题,并给出解决方案。
案例数据库:
CREATE TABLE product
(
pid character varying(32) NOT NULL,
"taskId" character varying(32) NOT NULL,
...
CONSTRAINT product_pkey PRIMARY KEY (pid)
)
使用Spring Boot(1.5.4.RELEASE), Hibernate5进行表格ORM时,对taskId字段的注解如下:
private String taskId;
@Column(name="taskId")
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
在命名策略spring.jpa.hibernate.naming.implicit-strategy和spring.jpa.hibernate.naming.physical-strategy不做任何配置,spring.jpa.hibernate.ddl-auto=update的情况下,启动SpringBoot,数据库表中生成字段“task_id”,意味着Hibernate的ORM找不到数据库表taskId字段,SpringBoot业务返回taskId值为null。
当把@Column(name="taskId")改为@Column(name="taskid"),系统报错,错误如下:
2017-11-01 19:24:41 ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: column product0_.taskid does not exist
建议:Perhaps you meant to reference the column "product0_.taskId" or the column "product0_.task_id".
位置:86
显然不能把@Column(name="taskId")改为@Column(name="taskid"),回到@Column(name="taskId"),当在pgAdmin中执行SQL语句 “select taskId from product”时,报错误:
ERROR: column "taskId" does not exist
LINE 1: select taskId from product
^
HINT: Perhaps you meant to reference the column "product.taskId" or the column "product.task_id".
********** Error **********
确实表字段taskId存在,是什么原因呢,我们发现在创建含大写字母的字段名称时,字段名称带双引号,改进SQL语句为“select 'taskId' from product”时,结果正确返回。接着,按照这个思路,改进@Column(name="taskId")为@Column(name="\"taskId\""),启动程序,发现数据库表还是新增了task_id字段,SpringBoot业务返回taskId值为null。
接下来SpringBoot添加命名策略:
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
SpringBoot正确返回taskId值为数据库中的值,同时,数据库表没有增加“task_id”字段。
另外,SpringNamingStrategy 在Hibernate5.1之后移除了,hibernate.ejb.naming_strategy将不再被支持,即spring.jpa.hibernate.naming-strategy的两个可选值org.hibernate.cfg.ImprovedNamingStrategy和org.hibernate.cfg.DefaultNamingStrategy不起作用了,而是被替换成了两个属性:spring.jpa.hibernate.naming.implicit-strategy和spring.jpa.hibernate.naming.physical-strategy了。