zoukankan      html  css  js  c++  java
  • mybatis源码分析——TypeHandler的使用与原理

    一:TypeHandler的定义

      mybatis是orm(对象关系模型)框架,需要实现pojo与数据库jdbcType的转换,当设置参数时,会调用到DefaultParameterHandler的setParameter方法,根据参数寻找不同的TypeHandler,将参数设置到PreparedStatement语句中。当返回结果时,会调用DefaultResultSetHandler的getPropertyMappingValue方法,根据propertyMapping找到TypeHandler,

    调用TypeHandler的getResult方法,从ResultSet中读取数据,然后封装到pojo上

    二:自定义TypeHandler的使用

    1: 定义一个币种的枚举

    public enum Currency {
    
        cny("CNY","人民币"),
        usd("USD","美元");
    
        private String code;
        private String desc;
    
        Currency(String code,String desc){
            this.code = code;
            this.desc = desc;
        }
    
        private static Map<String,Currency> map = new ConcurrentHashMap<>();
    
        static{
            for(Currency currency:values()){
                map.put(currency.code,currency);
            }
        }
    
        public static Currency getCurrencyByCode(String code){
            return map.get(code);
        }
    
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }
    

      

    定义一个关于币种转换的自定义TypeHandler,设置参数时,将枚举的币种值转换为字符串,设置到statement中,返回

    结果时,将字符串的值转换为枚举值

    public class CurrencyTypeHandler extends BaseTypeHandler<Currency> {
    
        @Override public void setNonNullParameter(PreparedStatement ps, int i, Currency parameter, JdbcType jdbcType)
            throws SQLException {
            ps.setString(i,parameter.getCode());
        }
    
        @Override public Currency getNullableResult(ResultSet rs, String columnName) throws SQLException {
            String currency = rs.getString(columnName);
            return Currency.getCurrencyByCode(currency);
        }
    
        @Override public Currency getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            return null;
        }
    
        @Override public Currency getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            return null;
        }
    }
    

      

    mybatis-config.xml中的配置:

        <typeHandlers>
            <typeHandler javaType="com.example.mybatis.model.Currency" jdbcType="VARCHAR"
                         handler="com.example.mybatis.model.CurrencyTypeHandler"/>
        </typeHandlers>
    

     

    mapper.xml中resultMap元素直接配置result子元素:

    <mapper namespace="com.example.mybatis.mapper.UserMapper">
    
    	<resultMap id="baseResultMap" type="com.example.mybatis.model.User">
    		<result column="id" property="id" jdbcType="INTEGER"></result>
    		<result column="name" property="name" jdbcType="VARCHAR"></result>
    		<result column="age" property="age" jdbcType="VARCHAR"></result>
    		<result column="currency" property="currency" jdbcType="VARCHAR"
    		typeHandler="com.example.mybatis.model.CurrencyTypeHandler"></result>
    	</resultMap>
    
    	<resultMap id="test" type="com.example.mybatis.model.User"/>
    
    	<insert id="insert" parameterType="com.example.mybatis.model.User">
    		insert into user (name,age) value(#{name},#{age})
    	</insert>
    
    	<select id="listUsers" resultMap="baseResultMap" parameterType="com.example.mybatis.model.User">
    		select * from user where name = #{name} and currency = #{currency,javaType=com.example.mybatis.model.Currency,
    		jdbcType=VARCHAR,typeHandler=com.example.mybatis.model.CurrencyTypeHandler}
    	</select>
    
    </mapper>
    

      

      

    测试代码:

        public static void main(String[] args) throws IOException {
            // 将mybatis-config的配置文件读入内存,生成字符流对象
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
    
            // 解析全局配置文件mybatis-config.xml
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = builder.build(reader);
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //       PageHelper.startPage(1,2);
    
            // 测试一级缓存:
            List<User> list = userMapper.listUsers("hello105", Currency.USD);
            System.out.println("第一次查询结果:" + list.size());
            System.out.println("第一次查询结果:" + list);
        }
    

      

    运行结果:字符串已经转换为枚举值:

    1:在mybatis-config.xml中配置 typeHandlers元素

    2:在mapper.xml中配置result子元素,配置typeHandler属性,在#{currency}中配置currency的jdbcType、javaType以及typeHandler属性

     或者不在mybatis-config.xml中配置typeHandler元素,直接在mapper.xml中的result子元素上配置typeHandler属性

    三:从源码层面分析一下如何实现的

    1:注册typeHandler

    解析typeHandler元素,然后调用register方法注册

    将解析后的javaType以及jdbcType ,handler缓存到map中

     

     设置参数的时候,调用preparedStatement 的setParameters方法:

    如果parameter是Currency类型,那么获取TypeHandler,调用typeHandler的setParameter方法:

    调用到自定义的CurrencyTypeHandler类,将枚举值Currency获取String值,set到preparedStatement中:

     

    返回值的时候,从resulstSet中取出字符串值,需要转换成Currency类型

    从ResultSet中获取结果:

    从resultSet中读取到字符串的值,然后根据字符串转为Currency类型对象

    总结:

    mybatis-config.xml中配置的typeHandlers元素可以不用配置,不配置就使用懒加载的方式,在解析sql时创建typeHandler对象,然后实现注册。

    1:参数设置时的转换,需要在参数上配置属性#{jdbcType= javaType= typeHandler=},在设置参数使,ps会根据参数属性找到typeHandler,然后转换

    2:获取结果时,需要在resultMap上面配置result子元素,在获取结果时,会根据参数属性找到typeHandler,然后拿到resultSet中的原始值,然后在自定义的

    TypeHandler中实现转换。

     

  • 相关阅读:
    智联招聘
    我的Linux以及软件配置(长期更新)
    关于Git的笔记
    PHP和HTML表单
    web学习笔记——CSS整理(一)
    新开通博客园
    Thinphp模板替换
    __APP__
    大步前行
    centos 7 添加环境变量
  • 原文地址:https://www.cnblogs.com/warrior4236/p/13183843.html
Copyright © 2011-2022 走看看