自定义类型的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(); } } }