一、什么是类型处理器(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 常用内置处理器
| Java 类型 | JDBC 类型 | 类型处理器 |
|---|---|---|
| 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"; } }