文章目录
- 一、TypeHandler概述
- 二、TypeHandler的工作原理
- 1.设置参数(Parameter Setting)
- 2.获取结果(Result Getting)
- 3.类型映射和转换规则
- 4.自定义TypeHandler的扩展性
- 三、自定义的具体实现
- 业务场景
- 分析需求
- 具体实现
一、TypeHandler概述
在 MyBatis 中,类型处理器(TypeHandler)扮演着 JavaType 与 JdbcType 之间转换的桥梁角色。它们用于在执行 SQL 语句时,将 Java 对象的值设置到 PreparedStatement 中,或者从 ResultSet 或 CallableStatement 中取出值。
二、TypeHandler的工作原理
TypeHandler在MyBatis中是一个核心概念,其工作原理主要涉及Java类型和JDBC类型之间的转换。下面将详细介绍TypeHandler的工作原理。
1.设置参数(Parameter Setting)
当Mybatis要执行一个sql语句时,(例如INSERT UPDATE等),它需要将Java对象的属性值设置到SQL语句对应的占位符上,这个过程就是通过TypeHandler来完成的。
具体步骤
- MyBatis会根据映射配置找到对应的TypeHandler实例。这个映射配置可以在MyBatis的配置文件或者XML文件中定义。
- TypeHandler实例会接收到Java对象中的属性值,并将其转换成JDBC能够识别的类型。这个转换过程是根据Java类型和JDBC类型之间的映射关系来完成的。
- 转换后的值会被设置到PreparedStatement对象对应的占位符上,以便数据库能够正常解析和执行SQL语句
2.获取结果(Result Getting)
当数据库进行查询操作并返回结果集合时,MyBatis需要将结果集中的数据提取出来,转换成Java对象中的对应属性类型,这个过程同样是由TypeHandler来完成的。
具体步骤
- MyBatis会根据映射配置找到对应的TypeHandler实例
- TypeHandler实例会从ResultSet对象中提取数据,这个提取过程是根据数据库字段和Java属性之间的映射关系来实现的。
- 提取出来的数据会被转换成Java对象中的对应属性类型,这个转换过程是由Java类型和JDBC类型之间的映射关系来完成的。
- 转换后的值会被设置到Java对象中对应的属性上,以便程序能够正确处理和使用这些数据。
3.类型映射和转换规则
TypeHandler的核心功能是实现Java类型和JDBC类型之间的映射和转换。这个映射和转换规则是根据Java类型和JDBC类型的特性和语义来定义的。
对于基本数据类型(如int、long、float等),MyBatis提供了内置的TypeHandler实现,这些实现能够直接将Java基本数据类型转换为对应的JDBC基本数据类型,反之亦然。
对于复杂数据类型(如自定义对象、集合等),MyBatis允许开发者自定义TypeHandler来实现复杂的类型转换逻辑。
4.自定义TypeHandler的扩展性
MyBatis的TypeHandler机制具有很高的扩展性。我们可以通过实现TypeHandler接口或继承BaseTypeHandler类来创建自定义的TypeHandler实现。自定义的TypeHandler可以实现任意复杂的类型转换逻辑,以满足特定业务需求。
此外,MyBatis还提供了丰富的API和扩展点来支持开发者自定义TypeHandler的注册和使用方式。我们可以通过配置文件、注解或编程方式将自定义的TypeHandler注册到MyBatis中,并在Mapper的XML映射文件中引用它们来处理特定的数据类型转换需求。
三、自定义的具体实现
业务场景
现在我们要对用户存入的手机号进行处理。存入手机号时需要进行加密操作,从数据库中取出手机号时,进行解密。
分析需求
TypeHandler是将指定类型转换成数据库支持的类型
- TypeHandler拿到手机号,进行加密
- TypeHandler加密后转换成指定JDBC类型存入数据库
- TypeHandler从数据库中取出JDBC类型
- TypeHandler拿到JDBC类型进行解密
- 返回手机号
具体实现
我们先定义一个Encrypt类。
这是我们自定义的类,后续会配合注解使用。
@Data
public class Encrypt {private String value;public Encrypt(){}public Encrypt(String value){this.value = value;}
}
@MappedTypes(Encrypt.class) //被处理的类型
@MappedJdbcTypes(JdbcType.VARCHAR) //转换成的JDBC类型
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {//手机号的加密我们采用aes加密方式//密钥private final byte[] KEY = "123456789abcdefg".getBytes(StandardCharsets.UTF_8);/*** 设置参数* @param ps SQL 预编译的对象* @param i 需要赋值的索引位置* @param parameter 原本位置i需要赋的值* @param jdbcType jdbc类型* @throws SQLException*/@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {if(parameter == null || parameter.getValue() == null){ps.setString(i,null);return;}AES aes = new AES(KEY);String str = aes.encryptHex(parameter.getValue());ps.setString(i, str);}/*** 获取值* @param rs 结果集* @param columnName 索引名* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {return decrypt(rs.getString(columnName));}/*** 获取值* @param rs 结果集* @param columnIndex 索引* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return decrypt(rs.getString(columnIndex));}/*** 获取值* @param cs 结果集* @param columnIndex 索引* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return decrypt(cs.getString(columnIndex));}//解密方法private Encrypt decrypt(String str){if (StringUtils.hasText(str)){return null;}return new Encrypt(SecureUtil.aes(KEY).decryptStr(str));}
}
注意
在properties文件中配置路径
mybatis.type-handlers-package=com.example.lottery.dao.handler