自定义 MyBatis 类型处理器的实践

在现代软件开发中,处理数据库与应用程序之间的数据类型转换是一个常见需求。特别是时间类型的处理,由于不同的系统和库可能使用不同的时间表示方式(如 MySQL 的 datetime 和 Java 的 Long 毫秒值),这需要我们进行适当的转换。本文将详细介绍如何通过 MyBatis 实现从 MySQL 的 datetime 类型到 Java 的 Long 类型毫秒值的转换。

第一步:实现自定义类型处理器

首先,我们需要创建一个自定义的类型处理器,用于将 Timestamp 转换为 Long 类型。以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.*;
import java.time.ZoneId;

/**
* MySql timestamp 类型 -> Java Long 类型 处理器
*
* @author HLJ
*/
public class TimestampToLongTypeHandler extends BaseTypeHandler<Long> {

private Long timestampToLong(Timestamp timestamp) {
return timestamp != null ? timestamp.toInstant().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null;
}

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

@Override
public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnName);
return timestampToLong(timestamp);
}

@Override
public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnIndex);
return timestampToLong(timestamp);
}

@Override
public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Timestamp timestamp = cs.getTimestamp(columnIndex);
return timestampToLong(timestamp);
}

}

第二步:注册类型处理器(可选)

注册类型处理器可以使转换全局生效,但需要注意这可能会影响其他类型的转换。以下是一个注册类型处理器的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import com.yohlj.app.common.mybatis.TimestampToLongTypeHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

/**
* MyBatis 配置
*
* @author HLJ
*/
@Configuration
@Slf4j
public class MyBatisConfig {

private static final Class<TimestampToLongTypeHandler> HANDLER_CLASS = TimestampToLongTypeHandler.class;

@Autowired
private SqlSessionFactory sqlSessionFactory;

/**
* 注册自定义类型处理器
*/
@PostConstruct
public void registerCustomTypeHandler() {
try {
if (sqlSessionFactory != null) {
TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
registerHandlerIfNotPresent(registry, Long.class, HANDLER_CLASS);
} else {
log.error("SqlSessionFactory is null");
}
} catch (Exception e) {
log.error("Error registering custom type handler", e);
}
}

private void registerHandlerIfNotPresent(TypeHandlerRegistry registry, Class<?> javaType, Class<?> handlerClass) {
if (!registry.hasTypeHandler(handlerClass)) {
registry.register(javaType, handlerClass);
log.info("...register custom type handler...");
} else {
log.info("Custom type handler already registered");
}
}

}

第三步:查询结果集显式指定处理器

在 MyBatis 的映射文件中,可以显式指定使用自定义的类型处理器。以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
<resultMap id="competitionTeamPageItemDTORm"
type="com.yohlj.app.domain.dto.CompetitionTeamPageItemDTO" autoMapping="true">
<result column="gmt_create" property="createTimeMillis"
typeHandler="com.yohlj.app.common.mybatis.TimestampToLongTypeHandler"/>
</resultMap>

<select id="getListForMgtTeamPage" resultMap="competitionTeamPageItemDTORm">
SELECT id AS 'team_id', gmt_create, competition_id
FROM competition_team
ORDER BY competition_id DESC, id ASC
LIMIT #{offset}, #{limit}
</select>

通过以上步骤,我们可以有效地将 MySQL 的 datetime 类型转换为 Java 的 Long 类型毫秒值,满足不同场景下的需求。


自定义 MyBatis 类型处理器的实践
https://blog.yohlj.cn/posts/4ec17667/
作者
Enoch
发布于
2023年11月18日
许可协议