mybatis的typeHandler
typeHandler作用:
1.传参时将javaType类型转换成jdbcType
2.结果集中ResultSet中取值时,jdbcType转换为javaType;
系统自定义的typeHandler:
mybatis系统内部定义了一系列的typeHandler;基本涵盖了我们正常使用的类型转换;如下
选取一个系统自定义的typeHandler看看;
在包org.apache.ibatis.type下有一个StringTypeHandler.java
源码如下:
public class StringTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } }
StringTypeHandler继承了BaseTypeHandler;而BaseTypeHandler实现了接口TypeHandler,
BaseTypeHandler中代码
/** * Copyright 2009-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.type; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.executor.result.ResultMapException; import org.apache.ibatis.session.Configuration; /** * @author Clinton Begin * @author Simone Tripodi */ public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> { protected Configuration configuration; public void setConfiguration(Configuration c) { this.configuration = c; } @Override public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { if (jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException e) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + e, e); } } else { try { setNonNullParameter(ps, i, parameter, jdbcType); } catch (Exception e) { throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + e, e); } } } @Override public T getResult(ResultSet rs, String columnName) throws SQLException { T result; try { result = getNullableResult(rs, columnName); } catch (Exception e) { throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e); } if (rs.wasNull()) { return null; } else { return result; } } @Override public T getResult(ResultSet rs, int columnIndex) throws SQLException { T result; try { result = getNullableResult(rs, columnIndex); } catch (Exception e) { throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from result set. Cause: " + e, e); } if (rs.wasNull()) { return null; } else { return result; } } @Override public T getResult(CallableStatement cs, int columnIndex) throws SQLException { T result; try { result = getNullableResult(cs, columnIndex); } catch (Exception e) { throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from callable statement. Cause: " + e, e); } if (cs.wasNull()) { return null; } else { return result; } } public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException; public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException; public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException; }
getResult分别用columnName和columnIndex从ResultSet中获取数据,CallableStatement表示从存储过程中获取结果及数据的方法;
下面我们创建自定义typeHandler
RoleMapper.java
package com.learn.charter2.mapper; import java.util.List; import com.learn.charter2.po.Role; public interface RoleMapper { Role getRole(Long id) throws Exception; int deleteRole(Long id) throws Exception; int insertRole(Role role) throws Exception; List<Role> findRole(Role role) throws Exception; }
Role.java
package com.learn.charter2.po; public class Role { private Long id; private String roleName; private String note; private Integer pk; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public Integer getPk() { return pk; } public void setPk(Integer pk) { this.pk = pk; } }
SqlSessionFactoryUtil.java
package com.learn.charter2.util; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtil { private static SqlSessionFactory sqlSessionFactory=null; private static final Class class_lock=SqlSessionFactoryUtil.class; private SqlSessionFactoryUtil() { } public static SqlSessionFactory initSqlSessionFactory(){ String resource="mybatis-config.xml"; InputStream inputStream=null; try { inputStream=Resources.getResourceAsStream(resource); } catch (Exception e) { Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE,null,e); } synchronized (class_lock) { if(sqlSessionFactory==null){ sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); } } return sqlSessionFactory; } public static SqlSession openSqlSession(){ if(sqlSessionFactory==null){ initSqlSessionFactory(); } return sqlSessionFactory.openSession(); } }
log4j.properties
log4j.rootLogger=debug,stdout log4j.logger.org.mybatis=debug log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p %d %C:%m%n
mybatis-config.xml
1 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 2 <configuration> 3 <typeHandlers> 4 <typeHandler handler="com.learn.charter2.util.MyStringTypeHandler" javaType="string" jdbcType="VARCHAR"/> 5 <typeHandler handler="com.learn.charter2.util.MyIntergerTypeHandler" javaType="int" jdbcType="VARCHAR"/> 6 </typeHandlers> 7 <environments default="development"> 8 <environment id="development"> 9 <transactionManager type="JDBC"> 10 <property name="autoCommit" value="false" /> 11 </transactionManager> 12 <dataSource type="POOLED"> 13 <property name="driver" value="com.mysql.jdbc.Driver" /> 14 <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> 15 <property name="username" value="root" /> 16 <property name="password" value="gys" /> 17 </dataSource> 18 </environment> 19 </environments> 20 <mappers> 21 <mapper resource="com/learn/charter2/mapper/roleMapper.xml" /> 22 </mappers> 23 </configuration>
roleMapper.xml
1 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 2 <mapper namespace="com.learn.charter2.mapper.RoleMapper"> 3 4 <resultMap type="com.learn.charter2.po.Role" id="roleMap"> 5 <id column="id" property="id" javaType="long" jdbcType="BIGINT"/> 6 <result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR"/> 7 <result column="note" property="note" typeHandler="com.learn.charter2.util.MyStringTypeHandler"/> 8 <result column="pk" property="pk" typeHandler="com.learn.charter2.util.MyIntergerTypeHandler"/> 9 </resultMap> 10 11 12 <select id="getRole" parameterType="long" resultMap="roleMap"> 13 select id,role_name as roleName,note from t_role where id=#{id} 14 </select> 15 16 <select id="findRole" parameterType="com.learn.charter2.po.Role" resultMap="roleMap"> 17 select id,role_name as roleName,note,pk from t_role 18 <where> 19 <if test="roleName !=null"> 20 role_name like concat('%',#{roleName,javaType=string,jdbcType=VARCHAR,typeHandler=com.learn.charter2.util.MyStringTypeHandler},'%') 21 </if> 22 <if test="pk !=null"> 23 and pk =#{pk,javaType=int,jdbcType=VARCHAR,typeHandler=com.learn.charter2.util.MyIntergerTypeHandler} 24 </if> 25 </where> 26 27 28 </select> 29 30 <insert id="insertRole" parameterType="com.learn.charter2.po.Role"> 31 insert into t_role 32 (role_name,note) 33 values 34 (#{roleName},#{note}) 35 </insert> 36 <delete id="deleteRole" parameterType="long"> 37 delete from t_role where id=#{id} 38 </delete> 39 </mapper>
MyIntergerTypeHandler.java
1 package com.learn.charter2.util; 2 3 4 import java.sql.CallableStatement; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 9 import org.apache.ibatis.type.JdbcType; 10 import org.apache.ibatis.type.MappedJdbcTypes; 11 import org.apache.ibatis.type.MappedTypes; 12 import org.apache.ibatis.type.TypeHandler; 13 import org.apache.log4j.Logger; 14 15 import sun.security.action.GetIntegerAction; 16 17 18 /** 19 * @MappedTypes({Integer.class}) 20 @MappedJdbcTypes(JdbcType.VARCHAR) 21 * 22 */ 23 public class MyIntergerTypeHandler implements TypeHandler<Integer> { 24 25 private Logger log=Logger.getLogger(MyIntergerTypeHandler.class); 26 27 private int getInt(String v){ 28 if("a".equals(v)){ 29 return 10; 30 }else if("b".equals(v)){ 31 return 20; 32 }else if("c".equals(v)){ 33 return 30; 34 }else{ 35 return 60; 36 } 37 } 38 @Override 39 public Integer getResult(CallableStatement cs, int index) 40 throws SQLException { 41 log.info("使用我的IntegerTypeHandler,CallbleStatment下表获取字符串"); 42 return getInt(cs.getString(index)); 43 } 44 45 @Override 46 public Integer getResult(ResultSet rs, int index) throws SQLException { 47 log.info("使用我的IntegerTypeHandler,ResultSet下标获取字符串"); 48 return getInt(rs.getString(index)); 49 } 50 51 @Override 52 public Integer getResult(ResultSet rs, String colName) throws SQLException { 53 log.info("使用我的IntegerTypeHandler,ResultSet 列名获取字符串"); 54 return getInt(rs.getString(colName)); 55 } 56 57 @Override 58 public void setParameter(PreparedStatement ps, int index, Integer value,JdbcType jt) throws SQLException { 59 log.info("使用我的IntegerTypeHandler==index:"+index+";value:"+value); 60 String v=""; 61 if(value==1){ 62 v="a"; 63 }else if(value==2){ 64 v="b"; 65 }else if(value==3){ 66 v="c"; 67 }else { 68 v="guoyansi"; 69 } 70 ps.setString(index, v); 71 } 72 }
MyStringTypeHandler.java
1 package com.learn.charter2.util; 2 3 4 import java.sql.CallableStatement; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 9 import org.apache.ibatis.type.JdbcType; 10 import org.apache.ibatis.type.MappedJdbcTypes; 11 import org.apache.ibatis.type.MappedTypes; 12 import org.apache.ibatis.type.TypeHandler; 13 import org.apache.log4j.Logger; 14 15 16 @MappedTypes({String.class}) 17 @MappedJdbcTypes(JdbcType.INTEGER) 18 public class MyStringTypeHandler implements TypeHandler<String> { 19 private Logger log=Logger.getLogger(MyStringTypeHandler.class); 20 21 @Override 22 public String getResult(CallableStatement cs, int index) 23 throws SQLException { 24 log.info("使用我的StringTypeHandler,CallbleStatment下表获取字符串"); 25 return cs.getString(index); 26 } 27 28 @Override 29 public String getResult(ResultSet rs, int index) throws SQLException { 30 log.info("使用我的StringTypeHandler,ResultSet下标获取字符串"); 31 return rs.getString(index); 32 } 33 34 @Override 35 public String getResult(ResultSet rs, String colName) throws SQLException { 36 log.info("使用我的StringTypeHandler,ResultSet 列名获取字符串"); 37 return rs.getString(colName); 38 } 39 40 @Override 41 public void setParameter(PreparedStatement ps, int index, String value, 42 JdbcType jt) throws SQLException { 43 value=value+"m"; 44 log.info("使用我的StringTypeHandler==index:"+index+";value:"+value); 45 ps.setString(index, value); 46 } 47 48 49 }
Charter2Main.java
1 package com.learn.charter2.main; 2 3 import java.util.List; 4 5 import org.apache.ibatis.session.SqlSession; 6 7 import com.learn.charter2.mapper.RoleMapper; 8 import com.learn.charter2.po.Role; 9 import com.learn.charter2.util.SqlSessionFactoryUtil; 10 11 public class Charter2Main { 12 public static void main(String[] args) { 13 SqlSession sqlSession = null; 14 try { 15 sqlSession = SqlSessionFactoryUtil.openSqlSession(); 16 RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); 17 Role role = new Role(); 18 role.setPk(10); 19 List<Role> list=roleMapper.findRole(role); 20 for(Role r:list){ 21 System.out.println("id:"+r.getId()+";roleName:"+r.getRoleName()+";note:"+r.getNote()+";pk:"+r.getPk()); 22 } 23 } catch (Exception e) { 24 System.err.println(e.getMessage()); 25 sqlSession.rollback(); 26 }finally{ 27 if(sqlSession!=null){ 28 sqlSession.close(); 29 } 30 } 31 } 32 33 }
自定义typeHandler的三个步骤:
1.定义typeHandler(MyIntergerTypeHandler.java MyStringTypeHandler.java)
2.配置typeHandler(mybatis-config.xml中3-6行)
3.指定入参中哪个字段使用typeHandler(mapper.xml中19-24行)
4.指定出参中哪个字段使用typeHandler(mapper.xml中7-8行)
以MyIntergerTypeHandler为例,运行一下Charter2Main.java
Charter2Main 中传入的pk参数是10,被typeHandler默默的转换成了guoyansi;
因为guoyansi在数据库中找到了值,在被返回到java中,guoyansi又被typeHandler转化成了60;
这个例子展示的就是Integer和String之间的转换。