简体   繁体   English

Java JDBC类型转换(Firebird / Jaybird):在使用getter或updater ResultSet方法之前检查值/类型兼容性吗?

[英]Java JDBC type conversion (Firebird / Jaybird): check value/type compatibility before using getter or updater ResultSet method?

If I understand (and test a sample JDBC code; using Jaybird for Firebird) well, even using a proper (= respecting the type mapping) updater method (eg ResultSet.updateString ), or maybe PreparedStatement parameter, can bring a "conversion exception". 如果我能很好地理解(并测试示例JDBC代码;使用Jaybird for Firebird),即使使用适当的(=尊重类型映射)更新程序方法(例如ResultSet.updateString )或PreparedStatement参数,也可以带来“转换异常” 。

Is it possible (and is it a good practice) to test before actually working with the result set (eg running an updater method) whether the actual Java Type/value can be safely converted to the target SQL data type? 在实际使用结果集(例如,运行更新程序方法)之前,是否有可能进行测试(并且是一种好习惯),因此可以将实际的Java类型/值安全地转换为目标SQL数据类型吗?

Is the "problem" just one-way? “问题”是单向的吗? Ie when converting back from SQL to Java (using getter method), is it guaranteed that the correct getter method will never fail (due to conversion problems)? 即,当从SQL转换回Java(使用getter方法)时,是否可以确保正确的getter方法永远不会失败(由于转换问题)?

My examples (Using Jaybird 3.0.2, JDK1.8): 我的示例(使用Jaybird 3.0.2,JDK1.8):

  • I need to update field: NUMERIC(9,2) . 我需要更新字段: NUMERIC(9,2) The corresponding updater is: ResultSet.updateBigDecimal(int columnIndex, BigDecimal x) . 相应的更新程序是: ResultSet.updateBigDecimal(int columnIndex, BigDecimal x) If I use x = new BigDecimal("123456789.1234") (bigger precision and scale), I (logically) get an exception: Exception in thread "main" org.firebirdsql.jdbc.field.TypeConversionException: Error converting to big decimal. 如果我使用x = new BigDecimal("123456789.1234") (更大的精度和小数位数 ),则(在逻辑上)我将获得异常: 线程“ main”中的异常org.firebirdsql.jdbc.field.TypeConversionException:转换为大十进制时出错。
  • I need to update field: VARCHAR(5) . 我需要更新字段: VARCHAR(5) The corresponding updater is: ResultSet.updateString(int columnIndex, String x) . 相应的更新程序是: ResultSet.updateString(int columnIndex, String x) If I use x = "123456" (longer string 6 > 5), I (logically) get an exception: Exception in thread "main" java.sql.DataTruncation: Data truncation. 如果我使用x = "123456" (较长的字符串6> 5),则我(在逻辑上)将获得异常: 线程“ main”中的异常java.sql.DataTruncation:数据截断。

Is there some general elegant way (not depending on specific type) how to check, whether an actual Java value/object can be "saved" to certain SQL field, other than just trying to run the query and catching the exceptions? 是否有一些通用的优雅方法(不取决于特定类型)如何检查,是否可以将实际Java值/对象“保存”到某些SQL字段,而不仅仅是尝试运行查询并捕获异常?

I would like to check the values already in my data editing dialog (before actually running the update query). 我想检查数据编辑对话框中已经存在的值(实际运行更新查询之前)。 Simple test "VALUE OK / NOT OK" would be fine (knowing just the target SQL type). 简单测试“ VALUE OK / NOT OK”就可以了(只知道目标SQL类型)。

It seems quite difficult for me to find all rules I would have to check "type by type" (ie for VARCHAR check string length, for NUMERIC check precision and scale etc. - but what else? or would that be sufficient? for integer and float types no need to check anything?). 对于我来说,要查找“逐个类型检查”的所有规则似乎非常困难(例如,对于VARCHAR检查字符串长度,对于NUMERIC检查精度和小数位等,但是还有什么?或者对于整数和浮点类型无需检查任何内容?)。

I tried to go through the Jaybird source codes but the "conversion process" is very complicated (and type-specific), I could not find the answer myself. 我尝试浏览Jaybird源代码,但是“转换过程”非常复杂(且特定于类型),我自己找不到答案。

JDBC does not provide anything to 'check' values before you actually set them, so Jaybird doesn't either: setting the value is the check. JDBC在实际设置值之前不提供任何“检查”值,因此Jaybird也不提供:设置值就是检查。 Exact behaviour is driver dependent, Jaybird attempts to validate on setting values, but other drivers might choose to defer this to the database itself (so the error would only occur on execute). 确切的行为取决于驱动程序,Jaybird会尝试验证设置值,但其他驱动程序可能选择将其推迟到数据库本身(因此错误只会在执行时发生)。

Normally, you would design your database and pick column types based on your business needs, which should naturally have lead to validation before you even try to put it in the database. 通常,您将设计数据库并根据业务需求选择列类型,这自然应该导致验证甚至没有尝试将其放入数据库中。

If you haven't done that until now, start adding validation to your input forms, by restricting lengths, using things like Hibernate Validator, or the validation of your UI framework. 如果您到目前为止还没有做过,请使用Hibernate Validator或UI框架的验证方法来限制长度,从而开始在输入表单中添加验证。

If you are working with highly dynamic requirements (eg user provided queries, etc), then you should use the features that JDBC does provide to create your own validation: The ParameterMetaData of a prepared statement and the ResultSetMetaData of a result set (also accessible from a prepared statement), specifically the getPrecision (and getScale ) of these objects, or maybe even things like DatabaseMetadata.getColumns . 如果您要处理高度动态的需求(例如,用户提供的查询等),则应使用JDBC确实提供的功能来创建自己的验证:准备好的语句的ParameterMetaData和结果集的ResultSetMetaData (也可以从以下位置访问)准备好的语句),特别是这些对象的getPrecision (和getScale ),甚至可能是诸如DatabaseMetadata.getColumns东西。

For a character type, getPrecision will indicate the max number of characters, for a numeric or decimal type you can use the max numbers of digits before the decimal point as precision - scale . 对于字符类型, getPrecision将指示最大字符数,对于numericdecimal类型,可以使用小数点的最大位数作为precision - scale

However in Jaybird this is not a 100% exact, for example getPrecision may return 9 for a numeric(8,2) if Jaybird can't identify the underlying column, and Jaybird (and Firebird) will actually allow up to precision 10 with some limitations (that is, unscaled max value of Integer.MAX_VALUE , ie 21474836.47 for this type). 但是在Jaybird中,此精度不是100%准确,例如,如果Jaybird无法识别基础列,则getPrecision可能会为numeric(8,2)返回9,而Jaybird(和Firebird)实际上会允许精度达到10限制(即Integer.MAX_VALUE缩放最大值,即此类型的21474836.47)。

As to your second question if using getters could cause a conversion exception: normal cases will not, but for example calling getInt() on a BIGINT with a value larger than Integer.MAX_VALUE or Integer.MIN_VALUE will. 关于您的第二个问题,使用getter是否会导致转换异常:正常情况不会,但是例如,对BIGINT调用getInt() ,该值大于Integer.MAX_VALUEInteger.MIN_VALUE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM