如果我能很好地理解(并测试一个示例JDBC代码;对Firebird使用Jaybird),即使使用适当的(=尊重类型映射)更新程序方法(例如ResultSet.updateString
)或PreparedStatement
参数,也会带来"转换异常"。
在实际使用结果集(例如运行更新程序方法)之前,是否可以测试实际的Java类型/值是否可以安全地转换为目标SQL数据类型?
"问题"只是单向的吗?也就是说,当从SQL转换回Java(使用getter方法)时,是否保证正确的getter方法永远不会失败(由于转换问题)?
我的例子(使用Jaybird 3.0.2、JDK1.8):
- 我需要更新字段:
NUMERIC(9,2)
。相应的更新程序是:ResultSet.updateBigDecimal(int columnIndex, BigDecimal x)
。如果我使用x = new BigDecimal("123456789.1234")
(更大的精度和规模),我(逻辑上)会得到一个异常:线程"main"org.firebirdsql.jdbc.field.TypeConversionException中出现异常:转换为大小数时出错 - 我需要更新字段:
VARCHAR(5)
。相应的更新程序为:ResultSet.updateString(int columnIndex, String x)
。如果我使用x = "123456"
(较长的字符串6>5),我(从逻辑上)会得到一个异常:线程"main"java.sql.DataTruncation:数据截断中的异常
除了尝试运行查询和捕获异常之外,是否有一些通用的优雅方法(不取决于特定类型)来检查实际的Java值/对象是否可以"保存"到特定的SQL字段?
我想检查数据编辑对话框中已经存在的值(在实际运行更新查询之前)。简单的测试"VALUE OK/NOT OK"就可以了(只知道目标SQL类型)。
我似乎很难找到我必须"逐个类型"检查的所有规则(即VARCHAR检查字符串长度、NUMERIC检查精度和小数位数等),但还有什么?或者这就足够了吗?对于整数和浮点类型,不需要检查任何内容?)。
我试着浏览Jaybird的源代码,但"转换过程"非常复杂(而且是特定类型的),我自己找不到答案。
JDBC在实际设置值之前不提供任何"检查"值的内容,所以Jaybird也不提供:设置值就是检查。确切的行为取决于驱动程序,Jaybird试图根据设置值进行验证,但其他驱动程序可能会选择将其推迟到数据库本身(因此错误只会在执行时发生)。
通常,您会根据业务需求设计数据库并选择列类型,这自然会在您尝试将其放入数据库之前进行验证。
如果到目前为止还没有做到这一点,那么可以通过限制长度、使用Hibernate Validator或UI框架的验证来开始向输入表单添加验证。
如果您正在处理高度动态的需求(例如用户提供的查询等),那么您应该使用JDBC提供的功能来创建自己的验证:准备好的语句的ParameterMetaData
和结果集的ResultSetMetaData
(也可以从准备好的声明中访问),特别是这些对象的getPrecision
(和getScale
),甚至可能是DatabaseMetadata.getColumns
之类的东西。
对于字符类型,getPrecision
将指示最大字符数,对于numeric
或decimal
类型,您可以将小数点前的最大位数用作precision - scale
。
然而,在Jaybird中,这并不是100%精确的,例如,如果Jaybird不能识别底层列,getPrecision
可能会为numeric(8,2)
返回9,而Jaybird(和Firebird)实际上会允许高达精度10的精度,但有一些限制(即,Integer.MAX_VALUE
的未缩放最大值,即此类型的21474836.47)。
至于您的第二个问题,使用getter是否会导致转换异常:正常情况下不会,但例如在值大于Integer.MAX_VALUE
或Integer.MIN_VALUE
的BIGINT
上调用getInt()
会。