上一博客主要是对单表的增删改查,比较简单,而且每个属性与 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>
来源: https://www.cnblogs.com/5ishare/p/8322076.html