实际上证明,想象比搬砖生活丰富的多。亲们,我用JPA实现查表操作的时候,Exception跳出来说表不存在,因为表名是全小写的,我还能怎样┑( ̄Д  ̄)┍。接下来,折腾才刚刚开始……不妨看下日志,内心异常的沉重
2019-09-24 17:31:16.407 ERROR 25864 --- [ XNIO-2 task-1] o.h.engine.jdbc.spi.sqlExceptionHelper : (conn=348) Table ‘4a.t_assets_mgr‘ doesn‘t exist 2019-09-24 17:31:16.420 ERROR 25864 --- [ XNIO-2 task-1] c.s.xxxx.aop.logging.LoggingAspect : Exception in com.xxx.yyyy.service.StaticQuadraa.initLevel() with cause = ‘org.hibernate.exception.sqlGrammarException: Could not extract ResultSet‘ and exception = ‘Could not extract ResultSet; sql [n/a]; nested exception is org.hibernate.exception.sqlGrammarException: Could not extract ResultSet‘ org.springframework.dao.InvalidDataAcce***esourceUsageException: Could not extract ResultSet; sql [n/a]; nested exception is org.hibernate.exception.sqlGrammarException: Could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225) at org.springframework.orm.jpa.AbstractEntityManagerfactorybean.translateExceptionIfPossible(AbstractEntityManagerfactorybean.java:527) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy195.getAllByBusinessName(UnkNown Source)
通常情况下解决这个问题,如果你的数据库是搭建在windows上面,而且你还是自己写玩的,第一步肯定是改MysqL的cnf,改成不区分大小写,这样总是可以的?不过现在都是在docker环境下,这操作,不行了啊,再装个Oracle又麻烦,怎么办呢?既然MysqL那边解决起来麻烦,我们在Java这想想办法吧。简单的分析一下过程,浏览器点按钮,发起请求到后台,Controller接到请求后通过service找到对应的DTO,DTO又通过Spring Data找到Hibernate从而实现的JPA规范,再转化成sql语句发送给数据库执行。因此只要能在发送前把表名改成大写就能解决问题了。
那么这个把表名改成大写或者小写,是在哪里执行的呢?还记得,JPA对字段有一个转换,比如a_b会转换成aB。这个当然不是Java内核实现的,这个是Hibernate的JPA实现做的。具体到代码,这个东西在spring中是org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy ,是默认使用的。Hibernate实现的这个,就是转换驼峰规则的功能。我注解里表名写的是大写,但是输出的sql语句里是小写,毫无疑问,这里有转换成小写的代码。目前,spring data jpa基于Hibernate5,而Hibernate5关于数据库命名策略的配置与之前版本略有不同,其采用implicit-strategy和physical-strategy两个配置项分别控制命名策略
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
这两个策略还是有点小小的区别的:
- implicit-strategy负责模型对象层次的处理,将对象模型处理为逻辑名称
- physical-strategy负责映射成真实的数据名称的处理,将上述的逻辑名称处理为物理名称。
- 当没有使用@Table和@Column注解时,implicit-strategy配置项才会被使用,当对象模型中已经指定时,implicit-strategy并不会起作用。
- physical-strategy一定会被应用,与对象模型中是否显式地指定列名或者已经被隐式决定无关。
这里提供两种解决方法:
-
可以在 springboot 项目中配置文件内加上配置行,设置命名为 无修改命名策略:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
-
重写命名策略中改表名为小写的方法:
@Component public class MysqLUpperCaseStrategy extends PhysicalNamingStrategyStandardImpl { private static final long serialVersionUID = 1383021413247872469L; @Override public Identifier toPhysicalTableName(Identifier name,JdbcEnvironment context) { // 将表名全部转换成大写 String tableName = name.getText().toupperCase(); return name.toIdentifier(name.getText()); } }
之后在我们需要在相关的
.yml
文件中使用自己实现的策略spring.jpa.hibernate.naming:physical-strategy: xx.xx.xx.config.Strategy.MysqLUpperCaseStrategy
这里我用了方法2,因为在后续的开发中,我们的开发前辈,对这个数据库下毒,一共用了驼峰、匈牙利、下划线,全小写四种命名风格,简直前无古人后无来者,念天地之悠悠,愿其早日作古而烁今,开局蓝buff必被抢,顺风必翻盘,斗地主3456少个7,高铁吃泡面少叉子,股票逢买必跌。
在这里我用了方法2,可以比较自由的对表名进行映射修改,而不依赖于他们的命名风格,以致,向先人敬礼!!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。