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之间的转换。