shardingsphere+mybatis LocalDateTime转换报错java.time.LocalDateTime cannot be cast to java.sql.Timestamp

报错信息

java.time.LocalDateTime cannot be cast to java.sql.Timestamp

Caused by: java.lang.ClassCastException: java.time.LocalDateTime cannot be cast to java.sql.Timestamp
	at org.apache.shardingsphere.shardingjdbc.jdbc.core.resultset.ShardingResultSet.getTimestamp(ShardingResultSet.java:251)
	at sun.reflect.GeneratedMethodAccessor75.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69)
	at com.sun.proxy.$Proxy166.getTimestamp(Unknown Source)
	at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38)
	at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28)
	at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:81)
	... 166 common frames omitted

问题分析

java 实体类中的字段类型为LocalDateTime,mysql 表中字段类型为datetime
未使用shardingsphere之前一切正常,使用shardingsphere之后才出现的这个错误
从报错信息上看是调用了org.apache.shardingsphere.shardingjdbc.jdbc.core.resultset.ShardingResultSet.getTimestamp()方法导致的 类型转换异常

// 在ShardingResultSet中getTimestamp方法如下
@Override
public Timestamp getTimestamp(final String columnLabel) throws SQLException {
	int columnIndex = columnLabelAndIndexMap.get(columnLabel);
    return (Timestamp) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, Timestamp.class), Timestamp.class);
}

在网上查了很多
有说依赖版本不兼容的
有说日期格式不正确的
有说要增加mybatis-typehandlers-jsr310依赖的
还有的说要修改数据库字段类型为timestamp
试了很多方法,问题还是存在,那我就另辟蹊径,下面就是我的解决方法

解决方案

重写LocalDateTimeTypeHandler 避免调用getTimestamp()方法
代码如下

package com.zixiu.framework.handler;

import org.apache.ibatis.type.JdbcType;
import org.springframework.stereotype.Component;

import java.sql.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/**
 * 重写LocalDateTimeTypeHandler ,解决shardingsphere + mybatis LocalDateTime转换问题
 *
 * @author ZiXiu
 */
@Component
public class LocalDateTimeTypeHandler extends org.apache.ibatis.type.LocalDateTimeTypeHandler {
    public LocalDateTimeTypeHandler() {
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
        ps.setTimestamp(i, new Timestamp(this.toTimeMillis(parameter)));
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Object object = rs.getObject(columnName);
        return object == null ? null : this.toLocalDateTime(object);
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Object object = rs.getObject(columnIndex);
        return object == null ? null : this.toLocalDateTime(object);
    }

    @Override
    public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
        return sqlTimestamp != null ? this.toLocalDateTime(sqlTimestamp.getTime()) : null;
    }

    private long toTimeMillis(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    private LocalDateTime toLocalDateTime(long timeMillis) {
        return new Date(timeMillis).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    private LocalDateTime toLocalDateTime(Object object) {
        if (object instanceof LocalDateTime) {
            return (LocalDateTime) object;
        } else if (object instanceof java.sql.Date) {
            java.sql.Date date = (java.sql.Date) object;
            return this.toLocalDateTime(date.getTime());
        } else if (object instanceof java.sql.Timestamp) {
            Timestamp sqlTimestamp = (Timestamp) object;
            return this.toLocalDateTime(sqlTimestamp.getTime());
        } else {
            System.out.println("实际类型是:" + object.getClass().getName());
            return null;
        }
    }
}

这样就不会报错了,如果有问题请评论!

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子休。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值