这不是我现在遇到的具体问题,只是我无法理解的问题。我在这里找不到任何问题,也在互联网上找不到关于这件事的信息
包装类,例如java.lang.Integer
(用于基元int
),从一开始就存在于Java中。但是JDBC的开发人员选择使用Java原语来实现getInt
和getLong
等方法。基元的问题在于它们不能表示SQL NULL
。
为了解决这个问题,JDBC开发人员编写了许多方法来在列为NULL
时返回默认基元值,如0
和false
,并引入了wasNull()
函数供用户检查它是否应该是null
。更糟糕的是,当许多其他方法(如PreparedStatement的setInt
)接受基元而不是包装对象时,用户必须有条件地使用setNull
将相应的列设置为NULL
。
我发现这为JDBCneneneba API的用户使用方式增加了不必要的复杂性。如果JDBC的ResultSet对象的getInteger
在列具有SQL NULL
时将Java null
作为Integer对象返回,那么它将非常方便,而无需检查wasNull
。Java的开箱会自动处理Integer对象必须分配给int
基元变量并将其转换为0
的情况。如果PreparedStatement有一个setInteger
方法,用户可以简单地使用它来设置合适列的值,包括SQL NULL
值,而无需检查它是否为null并恢复为setNull
。
即使到目前为止,也没有对JDBC进行任何更改来纠正这种异常情况。JDBC继续使用基元类型,即使我们已经使用了Java 1.7或1.8(我说得对吗?)。Java的内置装箱和取消装箱可以确保假设基元类型编写的旧应用程序在更新为使用包装器的JDBC版本下继续正常工作那么,为什么没有人愿意升级JDBC以使用包装器对象来代替基元呢
PS:很高兴听到JDBC这个荒谬问题的推荐替代解决方案。
虽然它不能完全回答您的问题,但JDBC 1.2规范包含以下"被拒绝"的设计选择:
A.8对GetObject与getXXX的支持
由于各种get/set方法和通用的getObject/setObject方法之间存在重叠,我们考虑放弃get/set的方法,只使用getObject/set对象。然而,对于程序员知道SQL类型的简单常见情况,生成的强制转换和提取非常乏味:int i = ((Integer)r.getObject(1, java.sql.Types.INTEGER)).intValue()
因此,我们决定在这种情况下稍微改变我们的极简主义原则,保留各种get/set方法作为大多数应用程序程序员的首选接口,同时也为工具构建器和复杂应用程序添加getObject/setObject方法
该规范的第14章还说:
例如,SQL INTEGER通常被映射到Java int。这支持一个简单的接口,用于将SQL值作为简单的Java类型进行读写。
第二章说:
提供与Java系统的其余部分一致的Java接口
据我所知,大多数Java API都使用基元类型而不是包装器类型。
同样在规范发布时(1.2的日期为1997年1月10日),没有装箱和取消装箱,使用Integer
等相当麻烦。例如,你根本无法直接用Integer
进行数学运算,你首先需要调用intValue()
来获得int
,然后才能真正进行任何基本运算,如加法、乘法等,然后你需要将结果转换回Integer
来存储它。这听起来是为基元设置getter和setter的一个很好的理由。
请记住,该规范是在1995年至1997年之间设计的,当时的内存相对更贵,而原语的包装对象只需要花费更多的内存。我相信一个简单的对象是8字节+基元字段的大小。对于成本为12字节而不是4字节的CCD_ 29。
总之,兼容性。JDBC API早在自动装箱之前就发布了,现在更改它需要所有第三方供应商更新和发布他们的JDBC实现——如果可能的话,这是一场后勤噩梦,而且那些使用JDBC API的供应商必须适应任何行为变化。
进行这种类型的更改的显而易见的方法是发布一个新的API,JDBC2,如果你愿意的话,尽管IMHO JDBC已经损坏到足以保证这一点,特别是考虑到JPA/Hibernate在大多数常见用法中隐藏了低级JDBC API。