MyBatis自定义EncryptedStringTypeHandler每个字段被重复调用两次问题咨询
问题原因
MyBatis在处理嵌套<collection>的普通result映射时,会执行两次类型处理器:第一次是处理结果集行、判断父子关联关系时的预读取,第二次是给子对象属性赋值时的正式读取,因此会出现两次调用的情况。而constructor构造注入逻辑会直接完成映射后一次性实例化对象,不会触发二次调用。
解决方案
方案1:使用constructor映射(已验证可行,优先推荐)
直接将子对象的映射改为构造器注入方式,示例配置如下:
<resultMap id="WorkspacePackageDTOMap" type="com.example.dto.WorkspacePackageDTO" autoMapping="true"> <id column="uid" property="uid" /> <collection property="participants" ofType="com.example.dto.ParticipantDTO"> <constructor> <idArg column="part_uid" javaType="String" name="uid"/> <arg column="given_name" javaType="String" name="givenName" typeHandler="com.example.dao.EncryptedStringTypeHandler"/> <arg column="middle_name" javaType="String" name="middleName" typeHandler="com.example.dao.EncryptedStringTypeHandler"/> <arg column="family_name" javaType="String" name="familyName" typeHandler="com.example.dao.EncryptedStringTypeHandler"/> <arg column="generation_qualifier" javaType="String" name="generationQualifier"/> <arg column="type" javaType="String" name="type"/> </constructor> </collection> </resultMap>
注意要确保ParticipantDTO存在对应参数名、参数类型的构造方法即可。
方案2:升级MyBatis版本
该重复调用类型处理器的问题是MyBatis低版本的已知缺陷,升级到3.5.10及以上版本即可直接修复,无需修改现有配置。
方案3:给自定义类型处理器增加本地缓存
如果不能调整配置也不能升级版本,可以在EncryptedStringTypeHandler的getResult方法中增加临时缓存,避免重复执行加密/解密逻辑:
public class EncryptedStringTypeHandler extends BaseTypeHandler<String> { // 用ThreadLocal缓存当前结果集已处理过的列值,避免重复计算 private final ThreadLocal<Map<String, String>> resultCache = ThreadLocal.withInitial(HashMap::new); @Override public String getResult(ResultSet rs, String columnName) throws SQLException { String key = rs.getStatement().hashCode() + ":" + columnName + ":" + rs.getRow(); if (resultCache.get().containsKey(key)) { String value = resultCache.get().get(key); // 读取完当前行后清空缓存避免内存泄漏 if (rs.isLast()) { resultCache.remove(); } return value; } String rawValue = rs.getString(columnName); String decryptedValue = decrypt(rawValue); // 你的原有解密逻辑 resultCache.get().put(key, decryptedValue); if (rs.isLast()) { resultCache.remove(); } return decryptedValue; } // 其余方法保持原有逻辑即可 }
内容的提问来源于stack exchange,提问作者SURAJ
相关产品推荐
相关产品推荐

