自定义类型的Typehandler
一、枚举类型的Typehandler
mybatis 在 处理 枚举类型 的读取和保存时,默认提供 了 两种方案:
1、mybatis 默认使用EnumTypeHandler 在处理枚举对象的时候保存的是枚举的名字。
2、 也可以改用:EnumOrdinalTypeHandler:【读取和保存都是 —》枚举的索引】
二、如何改用Typehandler
可以在mybatis-config.xml中配置,也可以在SQL映射文件中:
<typeHandlers>
<!--1、配置我们自定义的TypeHandler -->
<typeHandler handler="com.mybatis.typehandler.MyEnumEmpStatusTypeHandler" javaType="com.mybatis.typehandler.EmpStatus"/>
<!--2、也可以在处理某个字段的时候告诉MyBatis用什么类型处理器
增删改中:#{empStatus,typeHandler=xxxx}
查询中:
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmp">
<id column="id" property="id"/>
<result column="empStatus" property="empStatus" typeHandler=""/>
</resultMap>
注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据用的TypeHandler是一样的。
-->
</typeHandlers>
三、自定义Typehandler
这里用自定义枚举类型处理器举例:
1、自定义枚举类型:
EmpStatus.java
package com.mybatis.typehandler;
/**
* 希望数据库保存的是100,200这些状态码,而不是默认0,1或者枚举的名
* @author lfy
*
*/
public enum EmpStatus {
LOGIN(100,"用户登录"),LOGOUT(200,"用户登出"),REMOVE(300,"用户不存在");
private Integer code;
private String msg;
private EmpStatus(Integer code,String msg){
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
//按照状态码返回枚举对象
public static EmpStatus getEmpStatusByCode(Integer code){
switch (code) {
case 100:
return LOGIN;
case 200:
return LOGOUT;
case 300:
return REMOVE;
default:
return LOGOUT;
}
}
}
2、自定义typeHandler
EnumEmpStatusTypeHandler.java
package com.mybatis.typehandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
/**
* 1、实现TypeHandler接口。或者继承BaseTypeHandler
* @author lfy
*
*/
public class EnumEmpStatusTypeHandler implements TypeHandler<EmpStatus> {
/**
* 定义当前数据如何保存到数据库中
*/
@Override
public void setParameter(PreparedStatement ps, int i, EmpStatus parameter,
JdbcType jdbcType) throws SQLException {
// TODO Auto-generated method stub
System.out.println("要保存的状态码:"+parameter.getCode());
ps.setString(i, parameter.getCode().toString());
}
@Override
public EmpStatus getResult(ResultSet rs, String columnName)
throws SQLException {
// TODO Auto-generated method stub
//需要根据从数据库中拿到的枚举的状态码返回一个枚举对象
int code = rs.getInt(columnName);
System.out.println("从数据库中获取的状态码:"+code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(ResultSet rs, int columnIndex)
throws SQLException {
// TODO Auto-generated method stub
int code = rs.getInt(columnIndex);
System.out.println("从数据库中获取的状态码:"+code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
@Override
public EmpStatus getResult(CallableStatement cs, int columnIndex)
throws SQLException {
// TODO Auto-generated method stub
int code = cs.getInt(columnIndex);
System.out.println("从数据库中获取的状态码:"+code);
EmpStatus status = EmpStatus.getEmpStatusByCode(code);
return status;
}
}
3、在全局配置文件中,启用自定义类型
配置mybatis-config.xml,启用 EnumEmpStatusTypeHandler
<?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">
<configuration>
<typeHandlers>
<!--1、配置我们自定义的TypeHandler -->
<typeHandler handler="com.mybatis.typehandler.EnumEmpStatusTypeHandler" javaType="com.mybatis.typehandler.EmpStatus"/>
<!--2、也可以在处理某个字段的时候告诉MyBatis用什么类型处理器
增删改中:#{empStatus,typeHandler=xxxx}
查询中:
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmp">
<id column="id" property="id"/>
<result column="empStatus" property="empStatus" typeHandler=""/>
</resultMap>
注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据用的TypeHandler是一样的。
-->
</typeHandlers>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="Kitty521!" />
</dataSource>
</environment>
</environments>
<!-- 5、databaseIdProvider:支持多数据库厂商的;
type="DB_VENDOR":VendorDatabaseIdProvider
作用就是得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql;
MySQL,Oracle,SQL Server,xxxx
-->
<databaseIdProvider type="DB_VENDOR">
<!-- 为不同的数据库厂商起别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中
如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
-->
<mappers>
<!-- 新方法操作mybatis 需要 的配置文件 -->
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
四、测试自定义typeHandler
1、javabean对象
package com.mybatis.bean;
import com.mybatis.typehandler.EmpStatus;
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
//员工状态
private EmpStatus empStatus=EmpStatus.LOGOUT;
public EmpStatus getEmpStatus() {
return empStatus;
}
public void setEmpStatus(EmpStatus empStatus) {
this.empStatus = empStatus;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Employee(){
super();
}
public Employee(String lastName, String email, String gender) {
super();
this.lastName = lastName;
this.email = email;
this.gender = gender;
}
@Override
public String toString() {
return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
}
}
2、mapper接口对象
package com.mybatis.mapper;
import java.util.List;
import com.mybatis.bean.Employee;
import com.mybatis.bean.ProcPage;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
public Long addEmp(Employee employee);
}
3、SQL映射文件
<?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">
<mapper namespace="com.mybatis.mapper.EmployeeMapper">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
public Employee getEmpById(Integer id);
-->
<select id="getEmpById" resultType="com.mybatis.bean.Employee">
select id,last_name lastName,email,gender,empStatus from tbl_employee where id = #{id}
</select>
<!--public Long addEmp(Employee employee); -->
<insert id="addEmp" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gender,empStatus)
values(#{lastName},#{email},#{gender},#{empStatus})
</insert>
</mapper>
4、Junit单元测试
注意:要分两步操作,第一步先插入数据,观察数据库中枚举的保存形式,第二步再读取数据,观察枚举的读取形式。
package com.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.mybatis.bean.Employee;
import com.mybatis.bean.ProcPage;
import com.mybatis.mapper.EmployeeMapper;
import com.mybatis.typehandler.EmpStatus;
/**
* 1、接口式编程
* 原生: Dao ====> DaoImpl
* mybatis: Mapper ====> xxMapper.xml
*
* 2、SqlSession代表和数据库的一次会话;用完必须关闭;
* 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。(就是不要放在共享成员变量里面,A线程用完释放,B线程再用就为空了)
* 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
* (将接口和xml进行绑定)
* EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);
* 5、两个重要的配置文件:
* mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
* sql映射文件:保存了每一个sql语句的映射信息:
* 将sql抽取出来。
*
*/
public class MybatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testEnumUse(){
EmpStatus login = EmpStatus.LOGIN;
System.out.println("枚举的索引:"+login.ordinal());
System.out.println("枚举的名字:"+login.name());
System.out.println("枚举的状态码:"+login.getCode());
System.out.println("枚举的提示消息:"+login.getMsg());
}
/**
* 默认mybatis在处理枚举对象的时候保存的是枚举的名字:EnumTypeHandler
* 改变使用:EnumOrdinalTypeHandler:【读取和保存都是 --》枚举的索引,】
* @throws IOException
*/
@Test
public void testEnum() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
// 第一遍:先执行下面四句话,数据库中新建 一条记录 ,打开数据库并查看 枚举保存类型
// Employee employee = new Employee("test_enum", "[email protected]","1");
// mapper.addEmp(employee);
// System.out.println("保存成功"+employee.getId());
// openSession.commit();
// 第二遍:当数据库执行插入操作后,观察 插入是是 那一条 ID,然后再读取出来 ,查看 枚举类型
// Employee empById = mapper.getEmpById(11);
// System.out.println(empById.getEmpStatus());
}finally{
openSession.close();
}
}
}