column xxx is of type integer but expression is of type character varying。String的成员变量存到int的数据库列 报错
结论
-
为什么报该错?
因为类型不匹配。
Java中某个成员类型为字符串String
,而数据库中钙成员变量对应的列的类型却为数值int
,在向该列插入数据的时候就会报错。 -
如果在一个环境中报错,在另一个环境中却不报该错,可能的原因?
对PostgreSQL中的连接字符串中有个连接参数:stringtype=unspecified|varchar
对该参数的设置会影响数据库服务器端是否启用自己对传送过来的请求参数进行类型的自动判断
的功能。
场景
Java + Hibernate + PostgreSQL 11.13
某张数据表有一列为版本号,其定义为:
version_number int4
但是该字段在Java实体类的定义中,对应成员变量却为:
@Column(name="version_number")
private String versionNumber;
类型不匹配!
这是第一个错误:数据库列类型应该和程序语言实体类的对应字段相匹配。
问题接着来了,两套环境,SIT 和 UAT。
SIT程序正常运行,UAT却报错:
column 'version_number' is of type integer but expression is of type character varying
猜想
为什么?
为什么明明Java中成员属性和数据库中列类型明明不匹配,却在SIT环境正常运行(彷佛有个节点做了“类型自动转换”的工作),在另一个环境报错?
猜想:
- 两套环境的 PostgreSQL版本不一致,所以对这个特性的支持不同。
- 数据库服务器的版本相同,但是某个配置项不同,导致对该特性不同的效果。
- 其他配置。
问题的根源
在排除了1和2两种可能后,找到了出问题的点。
Java应用中配置的数据库连接字符串的链接参数,SIT和UAT是不同的(这是第二个错误,他导致问题在某个环境没有被测试出来)。
# SIT 有“自动转换类型”效果,程序可正常运行
jdbc:postgresql://192.168.0.234:5432/db_test?stringtype=unspecified
# UAT Java类型和数据库类型转换失败,报错。
jdbc:postgresql://192.168.0.234:5432/db_test
区别就在这个stringtype=unspecified
,来看看官网的说法:
如果stringtype设置为 unspecified,参数将作为非类型值发送到服务器,并且服务器将尝试推断适当的类型。
(此时只想对PostgreSQL的服务端说:我谢谢你,你还有这个功能呢我都没注意。)
见https://jdbc.postgresql.org/documentation/83/connect.html
Specify the type to use when binding PreparedStatement parameters set via setString(). If stringtype is set to varchar (the default), such parameters will be sent to the server as varchar parameters. If stringtype is set to unspecified, parameters will be sent to the server as untyped values, and the server will attempt to infer an appropriate type. This is useful if you have an existing application that uses setString() to set parameters that are actually some other type, such as integers, and you are unable to change the application to use an appropriate method such as setInt().
解决
修改Java代码中实体类成员属性的类型,使之与数据库列类型对应即可。
这样不管环境如何变化(数据库服务器版本是什么,有什么特殊的配置项如何变动,连接字符串中的参数如何变动),都不会出现类型转换的报错。
复盘
- Java对象定义的时候,就应该和数据库表结构进行对应。并至少测试过记录的增删改查(用例测试)。
- 数据库连接字符串在不同环境,未保持一致。
这导致了你在一个环境做好的工作,到了另一个环境,基础条件变了,很多依赖于基础条件的事情也会随之发生变化。
当然也包括其他能够造成在两套环境中某些基础变量发生变化
的成分,如数据库服务器版本,数据库服务器端参数,操作系统配置等。
代码Review。
自己检查是一方面,靠的是程序员自己的仔细和经验。但经验也会带来自大和粗心。
最好是能找其他人Review自己的代码。
review代码的人最好拥有以下特质:不会包庇自己,发现自己有问题会对自己说。
其他
-
https://www.runoob.com/manual/PostgreSQL/config-setting.html
-
如何查看PostgreSQL 服务器的版本号?
select version();
show SERVER_VERSION;
- 如何查看 PostgreSQL 服务器的配置项?
show all; -- 列出所有配置项的 name value description
show SERVER_VERSION; -- 想查看哪个配置项,就show那个配置项的名称
如果要修改的话,可以去搜索 set reset
带上postgresql
即可。
- 不同的客户端
在Java程序中通过连接字符串去连接,然后去操作PostgreSQL。
在一些GUI的数据库客户端(如 DBeaver) 去连接 PostgreSQL ,都是可以设置stringtype=unspecified
这样的连接参数项的。
自己找一找吧。