人大金倉kingbase invalid value for parameter client_encoding ANSI_X3.4-1968
背景
應(yīng)用連接數(shù)據(jù)庫的時候提示以下錯誤:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is com.kingbase8.util.KSQLException: ????????????: ?????? "client_encoding" ????????????: "ANSI_X3.4-1968"
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.cloud.autoconfigure.RefreshAutoConfiguration$JpaInvokerConfiguration.init(RefreshAutoConfiguration.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
... 26 common frames omitted
懷疑問題
-
jdbc驅(qū)動連接沒有設(shè)置和數(shù)據(jù)庫一致的編碼人大金倉的資料實在是少,甚至如何在jdbc連接設(shè)置編碼都無法找到,但是我們可以查找kingbase://協(xié)議踏幻,看看別人是怎么寫的察署,發(fā)現(xiàn)是這樣寫的:
*jdbc:kingbase8*://***:5419/cdb?useUnicode=true&characterEncoding=utf-8
屎暇。于是改上去,并沒有用。排除改方向 -
Druid不支持kingbase8在百度確實找到了這個說法,但是官網(wǎng)上不去茂嗓,沒辦法驗證這個說法。而且本地可以正常連接科阎,服務(wù)器連接不正常述吸。排除改方向
解決步驟
-
解決初始化連接返回的亂碼信息
com.kingbase8.util.KSQLException: ????????????: ?????? "client_encoding" ????????????: "ANSI_X3.4-1968"
在以上信息可以看到,這個應(yīng)該是鏈接的時候返回的锣笨,第一反應(yīng)就是去查看kingbase日志:
/data/kingbase/ES/V8/data/sys_log
蝌矛。可以看到如下信息:2021-04-14 16:18:43 CST 致命錯誤: 參數(shù) "client_encoding" 的值無效: "ANSI_X3.4-1968"
終于發(fā)現(xiàn)錯誤本體了票唆,但是,是什么導(dǎo)致了亂碼屹徘?亂碼肯定是中文不是英文了走趋,所以應(yīng)該有什么地址可以設(shè)置日志的編碼。不過kingbase基本和postgresql一致噪伊,所以按照postgresql的方法修改日志的編碼即可簿煌。大致找了下kingbase的日志氮唯,發(fā)現(xiàn)在這個文件
kingbase.conf
修改kingbase.conf日志編碼
lc_messages = 'zh_CN.UTF-8'
修改成:
lc_messages = 'en_US.UTF-8'
重啟kingbase:
sudo systemctl restart kingbase
之后可以看到j(luò)ava的日志打印正常了:
FATAL: invalid value for parameter "client_encoding": "ANSI_X3.4-1968"
-
調(diào)試源碼
根據(jù)提示信息查找,發(fā)現(xiàn)并沒有查看到有用的信息姨伟,所以嘗試調(diào)試源碼
在以下文件的對應(yīng)方法[
com.kingbase8.core.v3.ConnectionFactoryImpl#openConnectionImpl
]找到了108行關(guān)鍵代碼:newStream = new KBStream(socketFactory, hostSpec, connectTimeout); String client_encoding; if (KBProperty.CLIENT_ENCODING.get(info) == null) { client_encoding = System.getProperty("file.encoding"); info.setProperty("clientEncoding", client_encoding); LOGGER.log(Level.FINE, "Use current JVM default encoding {0}", client_encoding); } client_encoding = KBProperty.CLIENT_ENCODING.get(info); newStream.setEncoding(Encoding.getJVMEncoding(client_encoding));
可以看到初始化連接的時候惩琉,獲取了jvm_encoding。這里夺荒,我們可以調(diào)試一下瞒渠,在容器下的jvm_encoding究竟是什么編碼?
可以使用arthas修改容器class文件打印以下技扼,或者隨便在啟動的時候日志打印以下System.getProperty("file.encoding")伍玖。容器只記錄日志的輸出,所以可能使用System.out.println會無法顯示剿吻。
-
修改docker的jvm_encoding
在dockerfile添加以下代碼即可:
ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF8
完整的Dockerfile大致如下:
#FROM指令必須指定且需要在Dockerfile其他指令的前面,指定的基礎(chǔ)image可以是官方遠程倉庫中的窍箍,也可以位于本地倉庫 FROM livingobjects/jre8 # UTF-8 并配置環(huán)境 ENV LANG C.UTF-8 ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF8 #使容器中的一個目錄具有持久化存儲數(shù)據(jù)的功能,該目錄可以被容器本身使用 VOLUME /tmp #從src目錄復(fù)制文件到容器的dest丽旅。其中src可以是Dockerfile所在目錄的相對路徑椰棘,也可以是一個URL,還可以是一個壓縮包 ADD target/*.jar app.jar RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone #ADD wait-for-it.sh /wait-for-it.sh RUN bash -c 'touch /app.jar' #指定Docker容器啟動時執(zhí)行的命令榄笙,可以多次設(shè)置邪狞,但是只有最后一個有效。 ENTRYPOINT ["java","-Dfile.encoding=UTF8","-jar","/app.jar","--spring.profiles.active=test","&"]
修改重新build了之后可以發(fā)現(xiàn)办斑,連接正常了外恕。
總結(jié)
- 網(wǎng)上關(guān)于人大金倉的資料比較少,如果遇到問題乡翅,可以嘗試把關(guān)鍵字更換成postgresql再查看鳞疲,也許更容易查找到答案
- 需要意識到容器化部署下一些參數(shù)不一致。
- 網(wǎng)上找不到答案可以從源碼入手