You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data JDBC自定义CustomConversions转换器不生效问题

问题背景

需求是实现Spring Data JDBC实体类字段的自动加解密,JPA的AttributeConverter在Spring Data JDBC中不支持,因此尝试用框架自带的CustomConversions特性实现:

  • 首先自定义加密字段包装类型EncryptionDataType:
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class EncryptionDataType {
  private String value;

  @Override public String toString() {
    return value ;
  }
}
  • 在实体类中使用该自定义类型作为字段类型:
@Table("EMPLOYEE")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Data
public class Employee
{
    @Column("name")
    private EncryptionDataType name;
    @Id
    private Integer id;
    @Version
    private Long version;

}
  • 编写对应的读写转换器,预期框架自动将EncryptionDataType转成字符串存入MySQL的字符串列:
@WritingConverter
public class EncryptionDataTypeWriteConverter implements Converter<EncryptionDataType, String> {
  @Override public String convert(EncryptionDataType source) {
    return source.toString()+"add";
  }
}
@ReadingConverter
public class EncryptionDataTypeReadConverter implements Converter<String, EncryptionDataType> {

  @Override public EncryptionDataType convert(String source) {
    return new EncryptionDataType(source);
  }
}
  • 编写配置类注册转换器:
@Configuration
public class MyConfig {

@Bean
    protected JdbcCustomConversions JdbcConversion(Dialect dialect) {
            return new JdbcCustomConversions(
                Arrays.asList(new EncryptionDataTypeReadConverter(),new EncryptionDataTypeWriteConverter()));
    }
}
问题现象

配置完全不生效,运行时抛出SQL语法错误:

PreparedStatementCallback; bad SQL grammar [INSERT INTO `encryption_data_type` (`name`, `value`) VALUES (?, ?)]; nested exception is java.sql.SQLSyntaxErrorException: Table 'testschema.encryption_data_type' doesn't exist

从生成的SQL可以看出,框架没有将EncryptionDataType转换为字符串处理,反而将其识别为关联/嵌入式实体,尝试向不存在的encryption_data_type表插入数据。

后续补充了自定义配置,手动注册了数据源、JdbcOperations、事务管理器、JdbcConverter、JdbcMappingContext等相关Bean:

@Configuration
@EnableJdbcRepositories(transactionManagerRef = "CustomJdbcTranasactionManager", jdbcOperationsRef = "CustomJdbcOperationsReference", repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class, basePackages = {
    "com.java.testy"
})
@EnableAutoConfiguration(exclude = {
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class,
    org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration.class
})
public class MyConfig {

@Bean
    protected JdbcCustomConversions JdbcConversion(Dialect dialect) {
            return new JdbcCustomConversions(
                Arrays.asList(new EncryptionDataTypeReadConverter(),new EncryptionDataTypeWriteConverter()));
    }
// 手动创建datasource、CustomJdbcOperationsReference、CustomJdbcTranasactionManager、JdbcConverter、JdbcMappingContext、DataAccessStrategy、JdbcAggregateTemplate相关Bean
}
问题根因

手动定义JdbcMappingContext和JdbcConverterBean的时候,没有将自己注册的JdbcCustomConversions注入到这两个核心组件的实例中,框架初始化映射模型的时候根本读不到自定义转换器,就会默认把非基础类型、无对应转换器的自定义类型判定为嵌入式实体,按照嵌套实体的逻辑生成关联表插入SQL,最终报出表不存在的错误。

解决方案

修改手动创建JdbcMappingContext和JdbcConverter的代码,将自定义的JdbcCustomConversions注入进去完成初始化:

  • 初始化JdbcMappingContext时,调用setSimpleTypeHolder方法传入自定义Conversions持有的简单类型标识,让框架识别EncryptionDataType是需要转换的简单值类型,不是嵌套实体
  • 初始化JdbcConverter(一般用BasicJdbcConverter实现)时,把自定义的JdbcCustomConversions作为构造参数传入,让转换器加载自定义的加解密转换逻辑

示例配置代码:

@Bean
public JdbcMappingContext jdbcMappingContext(JdbcCustomConversions customConversions) {
    JdbcMappingContext mappingContext = new JdbcMappingContext();
    // 注入自定义转换器的简单类型持有器,标记自定义类型为值类型
    mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
    return mappingContext;
}

@Bean
public JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, 
                                   NamedParameterJdbcOperations operations,
                                   JdbcCustomConversions customConversions) {
    // 构造BasicJdbcConverter时传入自定义Conversions,加载读写转换器
    return new BasicJdbcConverter(
            mappingContext,
            o -> null,
            customConversions,
            null,
            operations.getJdbcOperations().getExceptionTranslator()
    );
}

配置完成后重启,框架就会正常识别自定义转换器,不会再把EncryptionDataType当成嵌套实体处理,字段读写时会自动走定义的加解密逻辑。

注意:如果同时自定义了JdbcAggregateTemplate和DataAccessStrategy,也要确保这两个组件引用的是正确配置了转换器的JdbcConverter实例,避免出现组件引用不一致的问题。

内容的提问来源于stack exchange,提问作者Ravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:15:46