为什么用Apache DBUtils来处理结果集得到数组时,会抛出LocalDateTime can‘t convert to java.util.Date异常

为什么用Apache DBUtils来处理结果集得到数组时,会抛出LocalDateTime can’t convert to java.util.Date异常

首先说结论,带着结论看会不那么懵逼:Apache DBUtils处理结果集用的是getObject()方法,我们自己处理结果集用的是getDate()方法,前者返回的是LocalDateTime类型,后者返回的是Date类型。

在使用Apache DBUtils之前,我模拟了一下它的底层实现,是用一个能够映射表信息的类的集合ArrayList来存储结果集ResultSet,代码如下

这是我的Actor映射类:
public class Actor{
	private int id;
	private String name;
	private String sex;
	private Date borndate;
	private String phone;
	/*get,set,构造器省略,构造器必须含有无参构造器,因为Apache dbutils底层利用反射通过Actor的无参构造器创建了对象*/
}
这是模拟APache dbutils底层的代码:
 public static void main(String[] args) {
        //传统的解决结果集不能高效利用的方法(创建一个对象集合保存返回的查询结果)
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        ArrayList<Actor> actors = new ArrayList<>();

        try {
            connection = JDBCUtilsByDruid.getConnection();
            String sql = "select *from actor where id >= ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,3);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String sex = resultSet.getString(3);
                Date borndate = resultSet.getDate(4);
                String phone = resultSet.getString(5);
                actors.add(new Actor(id,name,sex, borndate,phone));
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                System.out.println(resultSet.getClass());
                JDBCUtilsByDruid.closeConnection(resultSet,preparedStatement,connection);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < actors.size(); i++) {
            System.out.println(actors.get(i));
        }
这是我数据库中的actor表的列信息:在这里插入图片描述

注意 : 代码中映射类的borndate属性是Date类型的,我用getDate()方法从结果集中获取,虽然我结果集中的borndate在数据库是DateTime类型的,对应到java需要用LocalDateTime类型属性来获取,但是可以通过getDate()方法只获取到Date,相当于获取数据库中的Date类型,所以不会抛出异常。

但是在用Apache DBUtils工具类时,却抛出了如下异常:

Exception in thread "main" java.sql.SQLException: Cannot set borndate: incompatible types, cannot convert java.time.LocalDateTime to java.util.Date Query: select borndate from actor where id > ? Parameters: [1]

这是类转换异常:LocalDateTime类型无法转换成Date类型。显然,我在结果集中获取的对象是LocalDateTime型的,所以在赋值时才会报错。在Debug时,我发现确实是在将数据库中的borndate赋值给java的borndate时抛出了异常:

  if (this.isCompatibleType(value, firstParam)) {
                    setter.invoke(target, value);
                } else {
                    throw new SQLException("Cannot set " + prop.getName() + ": incompatible types, cannot convert " + value.getClass().getName() + " to " + firstParam.getName());
                }

上面的target便是映射类对象,value便是从结果集获取的borndate,但是此时的borndate已经是LocalDateTime类型了,所以程序进入else代码块报错。那么我么就要看这个value为什么是LocalDateTime类型。或者说看究竟是不是用getObject()方法获取的。

 private <T> T populateBean(ResultSet rs, T bean, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
        for(int i = 1; i < columnToProperty.length; ++i) {
            if (columnToProperty[i] != -1) {
                PropertyDescriptor prop = props[columnToProperty[i]];
                Class<?> propType = prop.getPropertyType();
                Object value = null;
                if (propType != null) {
                    value = this.processColumn(rs, i, propType);
                    if (value == null && propType.isPrimitive()) {
                        value = primitiveDefaults.get(propType);
                    }
                }

                this.callSetter(bean, prop, value);
            }
        }

        return bean;
    }

可以看到value是通过processColumn()方法赋值的,那么就进入这个方法:

protected Object processColumn(ResultSet rs, int index, Class<?> propType) throws SQLException {
		//这里用的是getObject(),返回的是LocalDateTime类型对象
        Object retval = rs.getObject(index);
        if (!propType.isPrimitive() && retval == null) {
            return null;
        } else {
            Iterator var5 = columnHandlers.iterator();

            while(var5.hasNext()) {
                ColumnHandler handler = (ColumnHandler)var5.next();
                if (handler.match(propType)) {
                    retval = handler.apply(rs, index);
                    break;
                }
            }

            return retval;
        }
    }

这时就可以看到,value是用的getObject()方法从数据库中获得borndate对象,而数据库中的borndate是DateTime类型,通过getObject()方法得到的是LocalDateTime类型,所以在将value赋值给target时,出现了类型转换异常。

简单的说就是:我们自己处理结果集时,用的是getDate()方法,得到的自然是Date类型,可以赋值给Actor中的borndate(也是Date类型)。但是Apache DBUtils使用getObject方法获取对象,在获取DateTime类型的对象时返回一个LocalDateTime类型的对象,这时我们赋值给Date类型对象,这两个类毫无干系,便会报类型转换异常错误。解决办法:1. 将映射类中的Date属性改为LocalDateTime属性。2. 将数据库中的DateTime类型改为Date类型(一般不在数据库中改数据类型)

`java.lang.NoClassDefFoundError: org.apache.commons.dbutils.QueryRunner` 错误通常发生在 Java 程序尝试引用 `QueryRunner` 类,而该类实际上并未在运行找到对应的定义。这可能是由于以下几个原因: 1. **依赖库未包含**:确保您的项目包含了 Apache Commons DBUtils 库。您需要在项目的构建文件(如 Maven 的 `pom.xml` 或 Gradle 的 `build.gradle` 文件中)添加相应的依赖项。例如,在 Maven 中,您可以将以下内容添加到 `<dependencies>` 部分: ```xml <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.8</version> </dependency> ``` 对于 Gradle,则是在 `dependencies` 部分添加类似下面的内容: ```groovy implementation 'commons-dbutils:commons-dbutils:1.9' ``` 版本可能有所不同,请根据实际情况调整。 2. **构建路径错误**:确认您已经正确地在 IDE(如 IntelliJ IDEA、Eclipse 等)中配置了项目的构建路径,确保库已经被正确添加进来,并且可以被项目发现并访问。 3. **编译环境问题**:有是因为构建工具未能成功将依赖库打包进最终的 `.jar` 或者应用容器中。请检查构建过程,确保所有必要的依赖都已包含在打包的结果中。 4. **类路径问题**:如果是在运行遇到此错误,可能是 Java 虚拟机 (JVM) 的类路径 (`classpath`) 中缺少必要的库。在这种情况下,需要确保 JVM 可以访问正确的类库目录或 JAR 文件。 5. **版本兼容性问题**:Apache Commons DBUtils 和其他库之间的版本可能存在兼容性问题。确认您使用的版本与其他组件相匹配,避免因版本差异导致的问题。 解决此类错误的基本步骤包括检查依赖管理、构建路径设置以及确保类路径正确。如果以上步骤都无法解决问题,可以查看详细的错误堆栈跟踪信息,它往往能提供更具体的线索帮助定位问题所在。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值