这几天在用spring boot开发项目, 在开发的过程中遇到一个问题hibernate在执行sql时,总会提示列名不存在。
寻找之后发现, 建表时,表统一采用了大写。hibernate会把大写统一转换成小写。且 postgreSQL对 大小写敏感(实际上如果把表名大写也会提示表名不存在)。
具体提示错误如下:
Caused by: org.postgresql.util.PSQLException: ERROR: column test0_.id does not exist
我的实体类是这么写的:
@Entity
@Table(name = "test")
public class Test implements Serializable {
private static final long serialVersionUID = -7768637914227571159L;
/**
* ID
*/
@Id
@GeneratedValue(generator = "idGenerator")
@GenericGenerator(name = "idGenerator", strategy = "identity")
@Column(name = "ID", nullable = false, length = 10)
private Long id ;
/**
* 姓名
*/
@Column(name = "NAME", nullable = true, length = 20)
private String name ;
把问题放在网上搜索之后,发现hibernate有一个命名策略
spring.jpa.hibernate.naming.strategy=org.hibernate.cfg.ImprovedNamingStrategy
当列名符合驼峰命名法时,@Column注解就无效了。如果想实现自己的需求需要继承ImprovedNamingStrategy实现自定义策略,但是当我实现自定义策略在application.properties里完成配置后,并没有起作用,后来发现这个策略只对hibernate5之前的版本起作用(实际上我用的是hibernate5,配不配置这个命名策略都没用,结果还是会将大写转为小写加下划线的形式)。
继续搜索之后发现hibernate5把上述策略拆分成了两个,分别是
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
之后我继承了PhysicalNamingStrategyStandardImpl类并重写了里面的方法,完成配置后,结果还是没有起作用(看了网上某篇博客是成功的,但是我这里尝试之后失败了)。
最后发现这样写可以保持表名和列名的大小写不变(上述的两个策略也要配置上)
// 表名
@Table("\"TEST\"")
// 字段
@Column("\"ID\"")
虽然这样有点麻烦,对于每个字段都要处理一下,但是毕竟也是解决问题的一个办法。
最好的解决办法
- 其实在设计数据库的时候,包括在MySQL上是不允许出现大写表名,并且相邻字母之间使用下划线做标识。
- 那么从现在开始,应该把你的数据库设计全部转成小写,并去除上面的代码。
参考
Spring Data JPA @Column 注解无效:
https://www.jianshu.com/p/ba87a9ee6001
Spring Boot + JPA(hibernate 5) 开发时,数据库表名大小写问题:
https://blog.51cto.com/4528195/1983780
spring data jpa在使用PostgreSQL表名大小写的问题解决:
https://blog.csdn.net/weixin_34000916/article/details/86011813
后记
后来我向项目组长建议把数据库表名和列名都转为小写加下划线的形式,最后的结果就是组长把这个艰巨的任务交给了我(哭哭)。