I have columns in a database table of type DATE
which I'd like mybatis to convert to java.time.ZonedDateTime
but it seems that the built in ZonedDateTimeHandler is not working. I get the following exception
Caused by: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'UPDATED_DATE' from result set. Cause: java.sql.SQLSyntaxErrorException: incompatible data type in conversion
at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:87)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createUsingConstructor(DefaultResultSetHandler.java:711)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createByConstructorSignature(DefaultResultSetHandler.java:694)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:658)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:631)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:398)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:355)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:329)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:302)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:195)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
... 36 common frames omitted
Caused by: java.sql.SQLSyntaxErrorException: incompatible data type in conversion
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCResultSet.getObject(Unknown Source)
at org.hsqldb.jdbc.JDBCResultSet.getObject(Unknown Source)
at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java)
at org.apache.ibatis.type.ZonedDateTimeTypeHandler.getNullableResult(ZonedDateTimeTypeHandler.java:38)
at org.apache.ibatis.type.ZonedDateTimeTypeHandler.getNullableResult(ZonedDateTimeTypeHandler.java:28)
at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85)
... 53 common frames omitted
Caused by: org.hsqldb.HsqlException: incompatible data type in conversion
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.error.Error.error(Unknown Source)
... 60 common frames omitted
It turned out that the default ZonedDateTimeTypeHandler assumes that the jdbc driver knows how to handle ZonedDateTime
which is NOT the case with hsqldb or oracle
public class ZonedDateTimeTypeHandler extends BaseTypeHandler<ZonedDateTime> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, ZonedDateTime parameter, JdbcType jdbcType) throws SQLException {
ps.setObject(i, parameter);
}
@Override
public ZonedDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getObject(columnName, ZonedDateTime.class);
}
...
}
I fixed this with a custom handler that uses setTimestamp(...)
and getTimestamp(...)
under the hood
@AllArgsConstructor
public class ZonedDateTimeTypeHandler extends BaseTypeHandler<ZonedDateTime> {
private final ZoneId zoneId;
@Override
public void setNonNullParameter(PreparedStatement ps, int i, ZonedDateTime parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, Timestamp.from(parameter.toInstant()));
}
@Override
public ZonedDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
Timestamp ts = rs.getTimestamp(columnName);
return ts == null ? null : ts.toInstant().atZone(zoneId);
}
@Override
public ZonedDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Timestamp ts = rs.getTimestamp(columnIndex);
return ts == null ? null : ts.toInstant().atZone(zoneId);
}
@Override
public ZonedDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Timestamp ts = cs.getTimestamp(columnIndex);
return ts == null ? null : ts.toInstant().atZone(zoneId);
}
}
Which I registered using the following code
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
ZoneId zoneId = ZoneId.of("UTC");
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("default", transactionFactory, dataSource);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(environment);
configuration.getTypeHandlerRegistry().register(ZonedDateTime.class, new ZonedDateTimeTypeHandler(zoneId));
configuration.addMapper(MyMapper.class);
return new SqlSessionFactoryBuilder().build(configuration);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.