• MyBatis之基于XML的属性与列名映射


    上一博客主要是对单表的增删改查,比较简单,而且每个属性与table表的列都是一一对应名字也一样,今天主要学习属性与table表列名不一致的处理,主要有两种一是属性与列名不一致,二是枚举的情况,这里暂时考虑的属性与列名不一致只是单表的情况,至于属性如果是其他model涉及表与表之间的关系的放在下一博客。不过先介绍几个其他的知识点。这些都是参考官网http://www.mybatis.org/mybatis-3/zh/index.html,大家也可以直接参考官网的。本篇博客还是在上一篇博客的基础上做的修改。

    一、Properties

    上一博客创建了一个DBConfig.xml,因为在上一博客只是做了关于数据库的配置,其实它不仅仅可以配置数据库的属性,还可以配置其他的好多属性,比如properties。所以从这篇开始把DBConfig.xml的名字改为了Config.xml。这里为了使用properties,先建了一properties文件:config.properties.

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis

    在Config.xml的configuration节点增加如下配置:

        <properties resource="config.properties">
          <property name="username" value="root"/>
          <property name="password" value="123456"/>
        </properties>

    如果再配置数据库连接的话就可以使用properties。

        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC" />
                <!-- 配置数据库连接信息 -->
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}" />
                    <property name="url" value="${url}" />
                    <property name="username" value="${username}" />
                    <property name="password" value="${password}" />
                </dataSource>
            </environment>
        </environments>
    View Code

    还有就是Properties在configuration节点设置的位置的问题,可以按照下图的顺序设置各个属性节点,因为在这个地方我也踩到了坑,就是在使用typeAlias的时候,我把typeAlias放在了mappers下面,然后就报错了。

    二、typeAlias

    alias别名,这个在sql种也经常用到,在上一博客种我们在UserMapper.xml种如果要参数类型或返回值类型时都会这样Cuiyw.MyBatis.Model.User写上User的全称,其实我们可以使用typeAlias来简化它来减少冗余。这样在用到Cuiyw.MyBatis.Model.User的地方都可以用别名User代替。

        <typeAliases>
            <typeAlias type="Cuiyw.MyBatis.Model.User" alias="User"/>
        </typeAliases>

    如果还觉得麻烦,可以直接指定包名就可以了。

        <typeAliases>
            <package name="Cuiyw.MyBatis.Model"/>
            <!-- <typeAlias type="Cuiyw.MyBatis.Model.User" alias="User"/> -->
        </typeAliases>

    三、属性与列名映射

    这是今天的主题,主要是两个内容,一是枚举类型映射,二是属性名与列名不一致怎么映射。

     1.自带枚举

    如果想使用mybatis自带的枚举类处理,有2种方式,一个是EnumTypeHandler,一个是EnumOrdinalTypeHandler。2者的区别是EnumTypeHandler直接存储name值,而EnumOrdinalTypeHandler会存储enum类里的序号值,此时数据库表字段一般用int类型的处理。

        <insert id="addUser" parameterType="User">
          <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
              SELECT LAST_INSERT_ID()
          </selectKey>
            insert into user(name,age,status) values (#{name},#{age},#{status,typeHandler=org.apache.ibatis.type.EnumTypeHandler})
        </insert>
        <insert id="addUser" parameterType="User">
          <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
              SELECT LAST_INSERT_ID()
          </selectKey>
            insert into user(name,age,status) values (#{name},#{age},#{status,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler})
        </insert>

    上面就是就是使用两种方式实现的新增,下面截图是两种方式在数据库的存储情况。

    2.resultMap

    上面在sql中的status参数中配置,但对于select的操作没有参数那该怎么办呢?于是resultMap出现了。其实它的作用还有好多,今天主要用它做个简单的例子,同时也演示列名和属性名不一致的情况。虽然先只考虑单表的情况,有时候数据库表的字段名与类的属性名也可能不是一一对应的,这种怎么解决呢?我们可以使用resultMap,用它来做关系映射,这样以后在用到的地方也只需要在select中增加属性resultMap,引用的它id就好也特别方便。这里要注意就是在resultMap设置的typeHandler与在insert中设置的要一致。

        <resultMap type="User" id="userResult">
            <result column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="age" property="age"/>
            <result column="status" property="status" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
        </resultMap>
        <select id="getUser" parameterType="int" 
            resultType="User" resultMap="userResult">
            select * from user where id=#{id}
        </select>

    还是使用昨天的代码,先增加一个,然后把增加的通过id查询出来。

    3.自定义枚举

    有时候mybatis自带的枚举并不能满足需求,那我们也可以自定义枚举。MyBatis提供了org.apache.ibatis.type.BaseTypeHandler类用于我们自己扩展类型转换器,上面的EnumTypeHandler和EnumOrdinalTypeHandler也都实现了这个接口。

    User类

    package Cuiyw.MyBatis.Model;
    
    public enum UserState {
    
        DISABLED(0),
        AVAILABLE(1);
        private int status;
        UserState(int status)
        {
            this.status=status;
        }
        
        public static UserState fromValue(int value)
        {
            for(UserState userState:UserState.values())
            {
                if(userState.status==value)
                {
                    return userState;
                }
            }
            throw new IllegalArgumentException("Cannot create evalue from value: " + value + "!");
        }
        
        public int getStatus()
        {
            return status;
        }
    }
    View Code

    EnumStatusHandler自定义枚举类  这里采用的EnumOrdinalTypeHandler模式,保存数字。在用的时候直接引用就好了。

    package Cuiyw.MyBatis.Model;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.ibatis.type.BaseTypeHandler;
    import org.apache.ibatis.type.JdbcType;
    
    public class EnumStatusHandler extends BaseTypeHandler<UserState> {
    
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, UserState parameter, JdbcType jdbcType)
                throws SQLException {
            // TODO Auto-generated method stub
            ps.setInt(i, parameter.getStatus());
        }
    
        @Override
        public UserState getNullableResult(ResultSet rs, String columnName) throws SQLException {
            // TODO Auto-generated method stub
            return UserState.fromValue(rs.getInt(columnName));
        }
    
        @Override
        public UserState getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            // TODO Auto-generated method stub
            return UserState.fromValue(rs.getInt(columnIndex));
        }
    
        @Override
        public UserState getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            // TODO Auto-generated method stub
            return UserState.fromValue(cs.getInt(columnIndex));
        }
    
    }
    View Code
        <resultMap type="User" id="userResult">
            <result column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="age" property="age"/>
            <result column="status" property="status" typeHandler="Cuiyw.MyBatis.Model.EnumStatusHandler"/>
        </resultMap>

    4.自定义枚举优化

    上面是针对每个枚举类型创建一个TypeHandler,那如果多的话岂不是很麻烦,那该怎么办呢?有什么优化的方法没?答案当然是有的啦。有单独的一个转到能应用多个,那就会联想的泛型。

    1.定义接口

    package Cuiyw.MyBatis.Model;
    
    public interface ValuedEnum {
        int getValue();
    }

    2.枚举实现接口

    package Cuiyw.MyBatis.Model;
    
    public enum UserState implements ValuedEnum {
    
        DISABLED(0),
        AVAILABLE(1);
        private int status;
        UserState(int status)
        {
            this.status=status;
        }
        
    //    public static UserState fromValue(int value)
    //    {
    //        for(UserState userState:UserState.values())
    //        {
    //            if(userState.status==value)
    //            {
    //                return userState;
    //            }
    //        }
    //        throw new IllegalArgumentException("Cannot create evalue from value: " + value + "!");
    //    }
    //    
    //    public int getStatus()
    //    {
    //        return status;
    //    }
    
        public int getValue() {
            // TODO Auto-generated method stub
            return status;
        }
    }
    View Code

    3.定义EnumTypeHandler

    在ValuedEnumTypeHandler构造函数中使用了getEnumConstants()方法,它以声明顺序返回一个数组,该数组包含构成此 class 对象所表示的枚举类的值,或者在此 class 对象不表示枚举类型时返回 null,这样就可以把枚举值与数字值对应起来放在map中。

    package Cuiyw.MyBatis.Model;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.ibatis.type.BaseTypeHandler;
    import org.apache.ibatis.type.JdbcType;
    
    public class ValuedEnumTypeHandler <E extends Enum<E>> extends BaseTypeHandler<E> {
    
        private Class<E> type;
        private Map<Integer, E> map = new HashMap<Integer, E>();
        
    
        public ValuedEnumTypeHandler(Class<E> type) {
            if (type == null) {
                throw new IllegalArgumentException("Type argument cannot be null");
            }
            this.type = type;
            E[] enums = type.getEnumConstants();
            if (enums == null) {
                throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
            }
            for (E e : enums) {
                ValuedEnum valuedEnum = (ValuedEnum) e;
                map.put(valuedEnum.getValue(), e);
            }
        }
        
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
            // TODO Auto-generated method stub
            ValuedEnum valuedEnum = (ValuedEnum) parameter;
            ps.setInt(i, valuedEnum.getValue());
        }
    
        @Override
        public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
            int i = rs.getInt(columnName);
            if (rs.wasNull()) {
                return null;
            } else {
                return getValuedEnum(i);
            }
        }
    
        @Override
        public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            int i = rs.getInt(columnIndex);
            if (rs.wasNull()) {
                return null;
            } else {
                return getValuedEnum(i);
            }
        }
    
        @Override
        public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            int i = cs.getInt(columnIndex);
            if (cs.wasNull()) {
                return null;
            } else {
                return getValuedEnum(i);
            }
        }
        private E getValuedEnum(int value) {
            try {
                return map.get(value);
            } catch (Exception ex) {
                throw new IllegalArgumentException(
                        "Cannot convert " + value + " to " + type.getSimpleName() + " by value.", ex);
            }
        }
    
    }
    View Code

    4.使用

        <resultMap type="User" id="userResult">
            <result column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="age" property="age"/>
            <result column="status" property="status" typeHandler="Cuiyw.MyBatis.Model.ValuedEnumTypeHandler"/>
        </resultMap>
  • 相关阅读:
    HTML onblur 事件属性
    插入光标颜色 | caret-color (Basic User Interface) – CSS 中文开发手册
    gc (Runtime) – Python 中文开发手册
    《宾狗》
    《凭什么相信你,我的CNN模型?(篇二:万金油LIME)》
    《凭什么相信你,我的CNN模型?(篇一:CAM和Grad-CAM)》
    《如何利用CAM(类激活图)动态可视化模型的学习过程》
    《Attention最新进展》
    TCP-IP四书五经
    《统计学习方法》
  • 原文地址:https://www.cnblogs.com/5ishare/p/8322076.html
Copyright © 2020-2023  润新知