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>
还有就是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; } }
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)); } }
<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; } }
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); } } }
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>
作者:社会主义接班人
出处:http://www.cnblogs.com/5ishare/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。