當JPA趕上MySQL表名全大寫+全小寫+駝峯+匈牙利四風格

我一直知道的MySQL在Linux上有字段名錶名等的大小寫問題,因而爲了不這個問題,選擇了下劃線和全小寫,心說雖然咱用的是JPA,只要使用註解寫清楚表名和字段名是大寫的,不也沒事麼。例如這樣java

當JPA趕上MySQL表名全大寫+全小寫+駝峯+匈牙利四風格

實際上證實,想象比搬磚生活豐富的多。親們,我用JPA實現查表操做的時候,Exception跳出來講表不存在,由於表名是全小寫的,我還能怎樣┑( ̄Д  ̄)┍。接下來,折騰纔剛剛開始……不妨看下日誌,心裏異常的沉重spring

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兩個配置項分別控制命名策略sql

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

這兩個策略仍是有點小小的區別的:docker

  • implicit-strategy負責模型對象層次的處理,將對象模型處理爲邏輯名稱
  • physical-strategy負責映射成真實的數據名稱的處理,將上述的邏輯名稱處理爲物理名稱。
  • 當沒有使用@Table和@Column註解時,implicit-strategy配置項纔會被使用,當對象模型中已經指定時,implicit-strategy並不會起做用。
  • physical-strategy必定會被應用,與對象模型中是否顯式地指定列名或者已經被隱式決定無關。

這裏提供兩種解決方法:數據庫

  1. 能夠在 springboot 項目中配置文件內加上配置行,設置命名爲 無修改命名策略:windows

    spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
  2. 重寫命名策略中改表名爲小寫的方法:瀏覽器

    @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文件中使用本身實現的策略springboot

    spring.jpa.hibernate.naming:physical-strategy: xx.xx.xx.config.Strategy.MySQLUpperCaseStrategy

    這裏我用了方法2,由於在後續的開發中,咱們的開發前輩,對這個數據庫下毒,一共用了駝峯、匈牙利、下劃線,全小寫四種命名風格,簡直前無古人後無來者,念天地之悠悠,願其早日做古而爍今,開局藍buff必被搶,順風必翻盤,鬥地主3456少個7,高鐵吃泡麪少叉子,股票逢買必跌。
    在這裏我用了方法2,能夠比較自由的對錶名進行映射修改,而不依賴於他們的命名風格,以至,向先人敬禮!!ide

當JPA趕上MySQL表名全大寫+全小寫+駝峯+匈牙利四風格

相關文章
相關標籤/搜索