mybatis之typeHandler
背景:
业务系统,多个选项(字符串数组,List),要存储到数据库中,数据表用的是 VARCHAR。
于是需要一种转换,
使用到的是 mybatis, 于是就使用 mybatis 的 typeHandler
代码
1、定义一个 typeHandler
import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.List; /** * mybatis-数组与字符串转换的handler */ @MappedTypes({List.class}) @MappedJdbcTypes({JdbcType.VARCHAR}) public class StringListTypeHandler extends BaseTypeHandler<List> { @Override public List getNullableResult(ResultSet rs, String columnName) throws SQLException { return getStringArray(rs.getString(columnName)); } @Override public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return this.getStringArray(rs.getString(columnIndex)); } @Override public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return this.getStringArray(cs.getString(columnIndex)); } @Override public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException { //由于BaseTypeHandler中已经把parameter为null的情况做了处理,所以这里我们就不用再判断parameter是否为空了,直接用就可以了 StringBuffer result = new StringBuffer(); for (Object value : parameter) { result.append(value).append(","); } result.deleteCharAt(result.length()-1); ps.setString(i, result.toString()); } private List getStringArray(String columnValue) { if (columnValue == null) return null; return Arrays.asList(columnValue.split(",")); } }
然后去声明一下这个 typeHandler
<typeHandlers> <typeHandler handler="com.carrot.demo.mybatis.handler.StringListTypeHandler"/> </typeHandlers>
mapper 接口是这样传参数的
int updateByRecordId(@Param("recordId")String recordId, @Param("instances")List<String> instances);
然后,
要注意的是,在查询和写入(更新,新增)在对应的字段上都要指定这个字段对应的typeHandler
<resultMap id="BaseResultMap" type="com.carrot.demo.mybatis.entity.RecordInstance"> <result column="record_id" jdbcType="VARCHAR" property="recordId"/> <result column="instances_info" jdbcType="VARCHAR" property="instances" typeHandler="com.carrot.demo.mybatis.handler.StringListTypeHandler"/> </resultMap> // 这个要注意的是,update / insert 的时候,也要指定这个字段绑定这个 handler, 不然的话,就会报错 // 会报一个 Not support this type 的错误(见报错详情) <update id="updateByRecordId"> UPDATE record_instances SET instances_info = #{instances,jdbcType=VARCHAR,typeHandler="com.carrot.demo.mybatis.handler.StringListTypeHandler} WHERE record_id = #{recordId,jdbcType=VARCHAR} </update>
报错详情
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType VARCHAR . Try setting a different JdbcType for this parameter or a different configuration property. Cause: dm.jdbc.driver.DMException: Not support this type at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:75) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:67) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:73) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:94) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:88) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) ~[mybatis-3.5.7.jar:3.5.7] at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) ~[mybatis-3.5.7.jar:3.5.7] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_261] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_261] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_261] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_261] at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) ~[mybatis-3.5.7.jar:3.5.7] at com.sun.proxy.$Proxy196.update(Unknown Source) ~[?:?] at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194) ~[mybatis-3.5.7.jar:3.5.7] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_261] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_261] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_261] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_261] at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433) ~[mybatis-spring-1.3.1.jar:1.3.1] ... 28 more
所以除了查询的时候要绑定,写入的时侯也要指定一下,不然肯定会造成类型不匹配的错误。因为传参一个List, 但sql是用一个 varchar 去接收,是不行的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南