一、什么是类型处理器(TypeHandler)?
1.1 核心概念
类型处理器是 MyBatis 中用于处理 Java 类型与 JDBC 类型之间转换的核心组件。它解决了两个关键问题:
参数映射:将 Java 对象转换为 JDBC 参数
结果映射:将 ResultSet 中的数据转换为 Java 对象
java
// 简化的类型处理器接口
public interface TypeHandler<T> {
// 设置 PreparedStatement 参数
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType);
// 从 ResultSet 获取结果
T getResult(ResultSet rs, String columnName);
T getResult(ResultSet rs, int columnIndex);
T getResult(CallableStatement cs, int columnIndex);
}
1.2 为什么需要类型处理器?
问题场景:
java
// 传统的做法:在业务代码中处理类型转换
public class UserMapper {
public User findById(Long id) {
User user = sqlSession.selectOne("findUserById", id);
// 手动转换 JSON 字段
String jsonAttr = user.getJsonAttr();
Map<String, Object> attributes = JSON.parse(jsonAttr);
user.setAttributes(attributes);
// 手动转换枚举
String statusStr = user.getStatus();
UserStatus status = UserStatus.valueOf(statusStr);
user.setStatusEnum(status);
return user;
}
}
使用类型处理器后:
java
public class UserMapper {
public User findById(Long id) {
// 所有转换自动完成
return sqlSession.selectOne("findUserById", id);
}
}
二、MyBatis 内置类型处理器
2.1 常用内置处理器
| String | VARCHAR, CHAR | StringTypeHandler |
| Integer | INTEGER | IntegerTypeHandler |
| Long | BIGINT | LongTypeHandler |
| Date | TIMESTAMP | DateTypeHandler |
| BigDecimal | DECIMAL | BigDecimalTypeHandler |
| boolean | BOOLEAN, BIT | BooleanTypeHandler |
| byte[] | BLOB, BINARY | BlobTypeHandler |
| Enum | VARCHAR | EnumTypeHandler |
| Enum | INTEGER | EnumOrdinalTypeHandler |
2.2 枚举处理器示例
java
// 枚举定义
public enum UserStatus {
ACTIVE("A", "活跃"),
INACTIVE("I", "禁用"),
LOCKED("L", "锁定");
private final String code;
private final String description;
UserStatus(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public static UserStatus fromCode(String code) {
for (UserStatus status : values()) {
if (status.code.equals(code)) {
return status;
}
}
throw new IllegalArgumentException("未知状态码: " + code);
}
}
// 自动使用 EnumTypeHandler(按名称存储)
// 数据库中存储 "ACTIVE", "INACTIVE" 等字符串
三、自定义类型处理器实战
3.1 继承 BaseTypeHandler
java
// JSON 类型处理器示例
@MappedTypes(Map.class) // 处理的 Java 类型
@MappedJdbcTypes(JdbcType.VARCHAR) // 处理的 JDBC 类型
public class JsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
// 配置 ObjectMapper
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
try {
String json = OBJECT_MAPPER.writeValueAsString(parameter);
ps.setString(i, json);
} catch (JsonProcessingException e) {
throw new SQLException("JSON 序列化失败", e);
}
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
String json = rs.getString(columnIndex);
return parseJson(json);
}
@Override
public Map<String, Object> getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String json = cs.getString(columnIndex);
return parseJson(json);
}
private Map<String, Object> parseJson(String json) {
if (StringUtils.isBlank(json)) {
return new HashMap<>();
}
try {
return OBJECT_MAPPER.readValue(json,
new TypeReference<Map<String, Object>>() {});
} catch (IOException e) {
throw new RuntimeException("JSON 解析失败: " + json, e);
}
}
}
3.2 枚举代码映射处理器
java
// 自定义枚举处理器:按代码存储
public class UserStatusTypeHandler extends BaseTypeHandler<UserStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
UserStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public UserStatus getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String code = rs.getString(columnName);
return rs.wasNull() ? null : UserStatus.fromCode(code);
}
@Override
public UserStatus getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
String code = rs.getString(columnIndex);
return rs.wasNull() ? null : UserStatus.fromCode(code);
}
@Override
public UserStatus getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String code = cs.getString(columnIndex);
return cs.wasNull() ? null : UserStatus.fromCode(code);
}
}
3.3 日期时间处理器
java
// Java 8 时间处理器
public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, Timestamp.valueOf(parameter));
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, String columnName)
throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnName);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
@Override
public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
Timestamp timestamp = cs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
}
3.4 集合类型处理器
java
// 逗号分隔的字符串转 List
public class StringListTypeHandler extends BaseTypeHandler<List<String>> {
private static final String DELIMITER = ",";
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
List<String> parameter, JdbcType jdbcType) throws SQLException {
String value = String.join(DELIMITER, parameter);
ps.setString(i, value);
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String value = rs.getString(columnName);
return parseString(value);
}
@Override
public List<String> getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
String value = rs.getString(columnIndex);
return parseString(value);
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String value = cs.getString(columnIndex);
return parseString(value);
}
private List<String> parseString(String value) {
if (StringUtils.isBlank(value)) {
return new ArrayList<>();
}
return Arrays.asList(value.split(DELIMITER));
}
}
四、配置类型处理器
4.1 XML 配置方式
xml
<!– mybatis-config.xml –>
<configuration>
<typeHandlers>
<!– 方式1:直接指定类 –>
<typeHandler handler="com.example.handler.JsonTypeHandler"/>
<!– 方式2:指定Java类型和处理器 –>
<typeHandler
javaType="java.util.Map"
handler="com.example.handler.JsonTypeHandler"/>
<!– 方式3:完整配置 –>
<typeHandler
javaType="java.util.Map"
jdbcType="VARCHAR"
handler="com.example.handler.JsonTypeHandler"/>
<!– 方式4:包扫描 –>
<package name="com.example.handler"/>
</typeHandlers>
</configuration>
4.2 Spring Boot 配置
java
// 配置类方式
@Configuration
public class MybatisConfig {
@Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer() {
return configuration -> {
// 注册类型处理器
configuration.getTypeHandlerRegistry().register(
Map.class,
JdbcType.VARCHAR,
JsonTypeHandler.class
);
// 注册枚举处理器
configuration.getTypeHandlerRegistry().register(
UserStatus.class,
UserStatusTypeHandler.class
);
};
}
}
// 或者在 MapperScan 中指定
@MapperScan(
basePackages = "com.example.mapper",
typeHandlers = {JsonTypeHandler.class, UserStatusTypeHandler.class}
)
4.3 注解配置
java
// 在实体类字段上直接指定
public class User {
private Long id;
private String name;
@TableField(typeHandler = JsonTypeHandler.class)
private Map<String, Object> attributes;
@TableField(typeHandler = UserStatusTypeHandler.class)
private UserStatus status;
// getters and setters
}
五、在 Mapper 中使用类型处理器
5.1 XML Mapper 中使用
xml
<!– UserMapper.xml –>
<mapper namespace="com.example.mapper.UserMapper">
<!– 结果映射中使用 –>
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="attributes" column="attributes"
typeHandler="com.example.handler.JsonTypeHandler"/>
<result property="status" column="status"
typeHandler="com.example.handler.UserStatusTypeHandler"/>
</resultMap>
<!– 查询语句 –>
<select id="selectById" resultMap="userMap">
SELECT * FROM users WHERE id = #{id}
</select>
<!– 插入语句 –>
<insert id="insert" parameterType="User">
INSERT INTO users (name, attributes, status)
VALUES (
#{name},
#{attributes, typeHandler=com.example.handler.JsonTypeHandler},
#{status, typeHandler=com.example.handler.UserStatusTypeHandler}
)
</insert>
<!– 更新语句 –>
<update id="update" parameterType="User">
UPDATE users SET
name = #{name},
attributes = #{attributes, typeHandler=com.example.handler.JsonTypeHandler},
status = #{status, typeHandler=com.example.handler.UserStatusTypeHandler}
WHERE id = #{id}
</update>
</mapper>
5.2 注解方式使用
java
@Mapper
public interface UserMapper {
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "attributes", property = "attributes",
typeHandler = JsonTypeHandler.class),
@Result(column = "status", property = "status",
typeHandler = UserStatusTypeHandler.class)
})
@Select("SELECT * FROM users WHERE id = #{id}")
User selectById(Long id);
@Insert("INSERT INTO users (name, attributes, status) " +
"VALUES (#{name}, " +
"#{attributes, typeHandler=com.example.handler.JsonTypeHandler}, " +
"#{status, typeHandler=com.example.handler.UserStatusTypeHandler})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
}
六、高级应用场景
6.1 多数据库适配
java
// 支持多种数据库的 JSON 处理
public class MultiDatabaseJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
private DatabaseType databaseType;
private ObjectMapper objectMapper = new ObjectMapper();
public MultiDatabaseJsonTypeHandler() {
// 可以通过配置文件或自动检测获取数据库类型
this.databaseType = detectDatabaseType();
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
try {
String json = objectMapper.writeValueAsString(parameter);
switch (databaseType) {
case MYSQL:
// MySQL 5.7+ 支持 JSON 类型
ps.setObject(i, json, Types.OTHER);
break;
case POSTGRESQL:
// PostgreSQL 使用 jsonb
ps.setObject(i, json, Types.OTHER);
break;
case ORACLE:
// Oracle 使用 CLOB 或 VARCHAR2
if (json.length() > 4000) {
ps.setClob(i, new StringReader(json));
} else {
ps.setString(i, json);
}
break;
default:
ps.setString(i, json);
}
} catch (JsonProcessingException e) {
throw new SQLException("JSON 序列化失败", e);
}
}
// 省略其他方法…
}
6.2 加密字段处理
java
// 数据库字段加密处理器
public class EncryptTypeHandler extends BaseTypeHandler<String> {
private static final String AES_KEY = "your-secret-key";
private static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding";
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
try {
String encrypted = encrypt(parameter);
ps.setString(i, encrypted);
} catch (Exception e) {
throw new SQLException("加密失败", e);
}
}
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String encrypted = rs.getString(columnName);
return encrypted != null ? decrypt(encrypted) : null;
}
private String encrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(AES_KEY.getBytes(), "AES"));
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
private String decrypt(String encrypted) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(AES_KEY.getBytes(), "AES"));
byte[] decoded = Base64.getDecoder().decode(encrypted);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted);
} catch (Exception e) {
throw new RuntimeException("解密失败", e);
}
}
}
6.3 通用泛型处理器
java
// 通用 JSON 处理器,支持任意类型
public class GenericJsonTypeHandler<T> extends BaseTypeHandler<T> {
private final Class<T> type;
private final ObjectMapper objectMapper;
public GenericJsonTypeHandler(Class<T> type) {
this.type = type;
this.objectMapper = new ObjectMapper();
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
T parameter, JdbcType jdbcType) throws SQLException {
try {
String json = objectMapper.writeValueAsString(parameter);
ps.setString(i, json);
} catch (JsonProcessingException e) {
throw new SQLException("JSON 序列化失败", e);
}
}
@Override
public T getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
private T parseJson(String json) {
if (StringUtils.isBlank(json)) {
return null;
}
try {
return objectMapper.readValue(json, type);
} catch (IOException e) {
throw new RuntimeException("JSON 解析失败: " + json, e);
}
}
// 省略其他 getResult 方法
}
6.4 注册泛型处理器
java
// 自定义 TypeHandlerRegistry
@Component
public class CustomTypeHandlerRegistry {
@PostConstruct
public void registerGenericHandlers() {
// 创建通用处理器实例
TypeHandler<Map<String, Object>> mapHandler =
new GenericJsonTypeHandler<>(Map.class);
TypeHandler<List<String>> listHandler =
new GenericJsonTypeHandler<>(List.class);
TypeHandler<UserConfig> configHandler =
new GenericJsonTypeHandler<>(UserConfig.class);
// 注册到 MyBatis
Configuration configuration = getMybatisConfiguration();
configuration.getTypeHandlerRegistry().register(
Map.class, JdbcType.VARCHAR, mapHandler);
configuration.getTypeHandlerRegistry().register(
List.class, JdbcType.VARCHAR, listHandler);
configuration.getTypeHandlerRegistry().register(
UserConfig.class, JdbcType.VARCHAR, configHandler);
}
}
七、最佳实践和注意事项
7.1 性能优化
java
// 使用缓存提升性能
public class CachedJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final ConcurrentHashMap<String, Map<String, Object>> CACHE =
new ConcurrentHashMap<>();
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
try {
String json = MAPPER.writeValueAsString(parameter);
ps.setString(i, json);
} catch (JsonProcessingException e) {
throw new SQLException("JSON 序列化失败", e);
}
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String json = rs.getString(columnName);
if (json == null) {
return null;
}
// 缓存命中
Map<String, Object> cached = CACHE.get(json);
if (cached != null) {
return cached;
}
// 解析并缓存
Map<String, Object> result = parseJson(json);
if (result != null) {
CACHE.put(json, result);
}
return result;
}
// 省略其他方法…
}
7.2 异常处理
java
// 增强的异常处理
public class SafeJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
Map<String, Object> parameter, JdbcType jdbcType) throws SQLException {
try {
String json = MAPPER.writeValueAsString(parameter);
ps.setString(i, json);
} catch (JsonProcessingException e) {
// 记录日志但不抛出异常,使用空对象替代
log.error("JSON 序列化失败,使用空对象", e);
try {
ps.setString(i, "{}");
} catch (SQLException ex) {
throw new SQLException("设置参数失败", ex);
}
}
}
@Override
public Map<String, Object> getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String json = rs.getString(columnName);
if (StringUtils.isBlank(json)) {
return new HashMap<>();
}
try {
return MAPPER.readValue(json,
new TypeReference<Map<String, Object>>() {});
} catch (IOException e) {
log.warn("JSON 解析失败,返回空对象: {}", json, e);
return new HashMap<>();
}
}
// 省略其他方法…
}
7.3 单元测试
java
// 类型处理器单元测试
@SpringBootTest
public class JsonTypeHandlerTest {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Test
public void testJsonTypeHandler() throws Exception {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 准备测试数据
User user = new User();
user.setName("张三");
Map<String, Object> attributes = new HashMap<>();
attributes.put("age", 25);
attributes.put("city", "北京");
attributes.put("hobbies", Arrays.asList("篮球", "音乐"));
user.setAttributes(attributes);
// 插入数据
mapper.insert(user);
session.commit();
// 查询数据
User retrieved = mapper.selectById(user.getId());
// 验证
assertNotNull(retrieved);
assertEquals("张三", retrieved.getName());
assertEquals(25, retrieved.getAttributes().get("age"));
assertEquals("北京", retrieved.getAttributes().get("city"));
// 验证 JSON 序列化/反序列化
String json = new ObjectMapper().writeValueAsString(attributes);
Map<String, Object> fromDb = retrieved.getAttributes();
String jsonFromDb = new ObjectMapper().writeValueAsString(fromDb);
assertEquals(json, jsonFromDb);
}
}
@Test
public void testNullHandling() {
JsonTypeHandler handler = new JsonTypeHandler();
// 测试空值处理
assertNull(handler.getNullableResult(null, 0));
// 测试空字符串
Map<String, Object> result = handler.parseJson("");
assertNotNull(result);
assertTrue(result.isEmpty());
}
}
八、Spring Boot 集成示例
8.1 完整项目结构
text
src/main/java/
├── com.example.demo/
│ ├── config/
│ │ ├── MybatisConfig.java
│ │ └── TypeHandlerConfig.java
│ ├── handler/
│ │ ├── JsonTypeHandler.java
│ │ ├── EncryptTypeHandler.java
│ │ └── UserStatusTypeHandler.java
│ ├── entity/
│ │ ├── User.java
│ │ ├── UserStatus.java
│ │ └── BaseEntity.java
│ ├── mapper/
│ │ └── UserMapper.java
│ ├── service/
│ │ └── UserService.java
│ └── DemoApplication.java
8.2 配置类
java
// TypeHandlerConfig.java
@Configuration
public class TypeHandlerConfig {
@Bean
@ConfigurationProperties(prefix = "mybatis.configuration")
public org.apache.ibatis.session.Configuration mybatisConfiguration() {
org.apache.ibatis.session.Configuration configuration =
new org.apache.ibatis.session.Configuration();
// 注册类型处理器
TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
// 注册自定义处理器
registry.register(JsonTypeHandler.class);
registry.register(EncryptTypeHandler.class);
registry.register(UserStatus.class, UserStatusTypeHandler.class);
// 注册通用处理器
registry.register(Map.class, JdbcType.VARCHAR,
new GenericJsonTypeHandler<>(Map.class));
registry.register(List.class, JdbcType.VARCHAR,
new GenericJsonTypeHandler<>(List.class));
return configuration;
}
@Bean
public SqlSessionFactory sqlSessionFactory(
DataSource dataSource,
org.apache.ibatis.session.Configuration configuration)
throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setConfiguration(configuration);
// 设置类型别名包
factory.setTypeAliasesPackage("com.example.demo.entity");
// 设置类型处理器包
factory.setTypeHandlersPackage("com.example.demo.handler");
return factory.getObject();
}
}
8.3 实体类示例
java
// User.java
@Data
@TableName("users")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(typeHandler = JsonTypeHandler.class)
private Map<String, Object> attributes;
@TableField(typeHandler = EncryptTypeHandler.class)
private String phone;
@TableField(typeHandler = UserStatusTypeHandler.class)
private UserStatus status;
@TableField(typeHandler = LocalDateTimeTypeHandler.class)
private LocalDateTime createTime;
@TableField(typeHandler = LocalDateTimeTypeHandler.class)
private LocalDateTime updateTime;
}
8.4 服务层使用
java
// UserService.java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User createUser(UserDTO userDTO) {
User user = new User();
user.setName(userDTO.getName());
// 设置属性,类型处理器会自动转换
Map<String, Object> attributes = new HashMap<>();
attributes.put("age", userDTO.getAge());
attributes.put("email", userDTO.getEmail());
attributes.put("preferences", userDTO.getPreferences());
user.setAttributes(attributes);
// 敏感信息自动加密
user.setPhone(userDTO.getPhone());
// 枚举自动转换
user.setStatus(UserStatus.ACTIVE);
userMapper.insert(user);
return user;
}
public User getUserById(Long id) {
// 所有转换在 MyBatis 层自动完成
return userMapper.selectById(id);
}
}
九、常见问题与解决方案
9.1 问题1:类型处理器不生效
原因分析:
未正确注册类型处理器
Mapper XML 中未指定 typeHandler
Java 类型与处理器不匹配
解决方案:
java
// 调试代码
@SpringBootTest
public class TypeHandlerDebugTest {
@Test
public void debugTypeHandler() {
Configuration configuration = sqlSessionFactory.getConfiguration();
TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
// 检查处理器是否注册
TypeHandler<?> handler = registry.getTypeHandler(Map.class, JdbcType.VARCHAR);
System.out.println("注册的处理器: " + handler);
// 检查 MappedStatement
MappedStatement ms = configuration.getMappedStatement(
"com.example.mapper.UserMapper.selectById");
ResultMap resultMap = ms.getResultMaps().get(0);
for (ResultMapping mapping : resultMap.getPropertyResultMappings()) {
System.out.println("字段: " + mapping.getProperty() +
", 处理器: " + mapping.getTypeHandler());
}
}
}
9.2 问题2:性能问题
优化策略:
使用缓存
避免在循环中创建 ObjectMapper
使用连接池管理 PreparedStatement
java
// 性能优化示例
public class OptimizedJsonTypeHandler extends BaseTypeHandler<Map<String, Object>> {
// 使用静态变量避免重复创建
private static final ThreadLocal<ObjectMapper> MAPPER_CACHE =
ThreadLocal.withInitial(() -> {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper;
});
// 使用软引用缓存解析结果
private static final Map<String, SoftReference<Map<String, Object>>> CACHE =
new ConcurrentHashMap<>();
@Override
public Map<String, Object> getNullableResult(ResultSet rs, String columnName)
throws SQLException {
String json = rs.getString(columnName);
if (json == null) {
return null;
}
// 检查缓存
SoftReference<Map<String, Object>> ref = CACHE.get(json);
if (ref != null) {
Map<String, Object> cached = ref.get();
if (cached != null) {
return cached;
}
}
// 解析并缓存
try {
ObjectMapper mapper = MAPPER_CACHE.get();
Map<String, Object> result = mapper.readValue(json,
new TypeReference<Map<String, Object>>() {});
CACHE.put(json, new SoftReference<>(result));
return result;
} catch (IOException e) {
throw new SQLException("JSON 解析失败", e);
}
}
}
9.3 问题3:版本兼容性
java
// 多版本兼容的处理器
public class VersionAwareTypeHandler<T> extends BaseTypeHandler<T> {
private final Map<String, TypeHandler<T>> versionHandlers = new HashMap<>();
public VersionAwareTypeHandler() {
// 注册不同版本的处理器
versionHandlers.put("1.0", new V1TypeHandler());
versionHandlers.put("2.0", new V2TypeHandler());
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
T parameter, JdbcType jdbcType) throws SQLException {
String version = getCurrentVersion();
TypeHandler<T> handler = versionHandlers.get(version);
if (handler != null) {
handler.setParameter(ps, i, parameter, jdbcType);
} else {
// 使用默认处理器
ps.setObject(i, parameter);
}
}
private String getCurrentVersion() {
// 从配置文件或上下文获取版本号
return "2.0";
}
}


