MyBatis系列第九篇:MyBatis插件

文章目录

  • 一、插件原理
  • 二、插件开发
    • 1.插件开发步骤
    • 2.Interceptor接口
  • 三、扩展分页插件
    • 1、PageHelper插件进行分页
    • 2、批量操作
  • 三、存储过程
  • 四、自定义类型处理器

一、插件原理

MyBatis 在 四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。

MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。

默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:四大对象

 Executor (update, query, flushStatements, commit, rollback,getTransaction, close, isClosed)
 ParameterHandler (getParameterObject, setParameters)
 ResultSetHandler (handleResultSets, handleOutputParameters)
 StatementHandler (prepare, parameterize, batch, update, query)

1、创建四大对象的ParameterHandler

BaseStatementHandler.java
  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

2、每个创建出来的对象不是直接返回的,而是调用pluginAll()

  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

插件原理
在四大对象创建的时候

1、每个创建出来的对象不是直接返回的,而是调用pluginAll()返回

2、获取所有的interceptor(拦截器)(插件需要实现的接口)调用interceptor.plugin(target);返回target包装后的对象

3、插件机制、我们可以使用插件为目标对象创建一个代理对象(AOP动态代理)

我们的插件可以为四大对象创建出代理对象
代理对象可以拦截到四大对象的每一个执行方法

插件执行流程
1、按照插件注解声明,按照插件配置顺序调用插件plugin方法,生成被拦截对象的动态代理
2、多个插件依次生成目标对象的代理对象,层层包裹,先声明的先包裹;形成代理链
3、目标方法执行时依次从外到内执行插件的intercept方法。
MyBatis系列第九篇:MyBatis插件_第1张图片

4、多个插件情况下,我们往往需要在某个插件中分离出目标对象。可以借助MyBatis提供的SystemMetaObject类来进行获取最后一层的h以及target属性的值

二、插件开发

1.插件开发步骤

1、编写Interceptor接口的实现类

package com.ming.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Statement;
import java.util.Properties;

/**
 *
 *
 * 使用@Intercepts注解完成插件签名:告诉mybatis当前插件用来拦截哪个对象的哪个方法
 */
//type:拦截的四大对象之一StatementHandler(处理SQL语句预编译设置参数),method:对象的方法(parameterize设置参数) args:对象参数的列表
@Intercepts(
        {
             @Signature(type = StatementHandler.class,method ="parameterize",args = Statement.class)
        })
public class MyPlugin implements Interceptor{

    /**
     * 拦截目标对象的目标方法的执行
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyPlugin....intercept:自定义插件拦截的目标方法"+invocation.getMethod());
        //放行、执行目标方法
        Object proceed = invocation.proceed();
        //返回执行后的返回值
        return proceed;
    }

    /**
     * plugin:包装目标对象的,所谓的包装就是为目标对象创建代理对象
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象"+target);
        //可以借助 Plugin.wrap()方法使用当前的Intercept包装我们目标对象
        Object wrap = Plugin.wrap(target,this);

        //返回为当前target创建的动态代理
        return wrap;
    }

    /**
     * 将插件注册时的Property属性设置进来
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息properties:"+properties);
    }


}

2、使用@Intercepts完成插件签名

3、将写好的插件注册到全局配置文件中

    <!-- 注册插件property 属性会被插件的获取到-->
    <plugins>
        <plugin interceptor="com.ming.plugin.MyPlugin">
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </plugin>
    </plugins>

测试运行一个查询方法

    @Test
    public void testInterface() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = employeeMapper.getEmpByID(1);
            System.out.println(employee);
            Employee employee2 = employeeMapper.getEmpByID(5);
            System.out.println(employee2);
            System.out.println(employee==employee2);

        }finally {
            sqlSession.close();
        }
    }

MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.CachingExecutor@3f197a46
DEBUG 05-27 17:04:35,300 Cache Hit Ratio [com.ming.dao.EmployeeMapper]: 0.0  (LoggingCache.java:62) 
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.scripting.defaults.DefaultParameterHandler@5b239d7d
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.resultset.DefaultResultSetHandler@6d763516
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.statement.RoutingStatementHandler@37afeb11
DEBUG 05-27 17:04:35,305 ==>  Preparing: select id,last_name AS lastName,gender,email from tbl_employee WHERE id = ?   (BaseJdbcLogger.java:145) 
MyPlugin....intercept:自定义插件拦截的目标方法public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
DEBUG 05-27 17:04:35,319 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 

多个插件运行的流程

左一单个插件代理对象 右一多个插件代理对象
MyBatis系列第九篇:MyBatis插件_第2张图片

2.Interceptor接口

常用代码:从代理链中分离真实被代理对象

//1、分离代理对象。由于会形成多次代理,所以需要通过一个
while 循环分离出最终被代理对象,从而方便提取信息
MetaObject metaObject = SystemMetaObject. forObject(target);
e while  (metaObject.hasGetter( "h" )) {
Object h = metaObject.getValue("h");
metaObject = SystemMetaObject. forObject(h);
}
//2、获取到代理对象中包含的被代理的真实对象
Object obj = metaObject.getValue("target");
//3、获取被代理对象的MetaObject方便进行信息提取
MetaObject forObject = SystemMetaObject. forObject(obj);

可以在目标方法放行前后做一些操作、动态修改mybatis运行流程

比如:动态改变sql运行的参数、比如以前查询id为1的员工、实际从数据库查询3号员工

package com.ming.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Statement;
import java.util.Properties;

/**
 *
 *
 * 使用@Intercepts注解完成插件签名:告诉mybatis当前插件用来拦截哪个对象的哪个方法
 */
//type:拦截的四大对象之一StatementHandler(处理SQL语句预编译设置参数),method:对象的方法(parameterize设置参数) args:对象参数的列表
@Intercepts(
        {
             @Signature(type = StatementHandler.class,method ="parameterize",args = Statement.class)
        })
public class MyPlugin implements Interceptor{

    /**
     * 拦截目标对象的目标方法的执行
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyPlugin....intercept:自定义插件拦截的目标方法"+invocation.getMethod());
        //intercept()可以在目标方法放行前后做一些操作、动态修改mybatis运行流程
        //操作:动态改变sql运行的参数、比如以前查询id为1的员工、实际从数据库查询3号员工
        //拿到StatementHandler-->ParameterHandler->parameterObject的值
        //拦截到的目标对象
        Object target = invocation.getTarget();
        //拿到target元数据
        System.out.println("拦截到的目标对象:"+invocation.getTarget());
        //1、分离代理对象。由于会形成多次代理,所以需要通过一个 while 循环分离出最终被代理对象,从而方便提取信息
        MetaObject metaObject = SystemMetaObject.forObject(target);
        //2、获取到代理对象中包含的被代理的真实对象
        Object value = metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("sql语句用的参数是:"+value);
        //修改完sql语句要用的参数
        metaObject.setValue("parameterHandler.parameterObject","5");


        //放行、执行目标方法
        Object proceed = invocation.proceed();
        //返回执行后的返回值
        return proceed;
    }

    /**
     * plugin:包装目标对象的,所谓的包装就是为目标对象创建代理对象
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象"+target);
        //可以借助 Plugin.wrap()方法使用当前的Intercept包装我们目标对象
        Object wrap = Plugin.wrap(target,this);

        //返回为当前target创建的动态代理
        return wrap;
    }

    /**
     * 将插件注册时的Property属性设置进来
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息properties:"+properties);
    }


}

测试:

    /**
     * mybatis运行原理以查询为例
     * @throws IOException
     */
    @Test
    public void testInterface() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = employeeMapper.getEmpByID(1);
            System.out.println(employee);

        }finally {
            sqlSession.close();
        }
    }

打印结果:SQL语句查询id是1的员工,我们使用拦截器设置了参数为5的员工,查询结果如下

MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.CachingExecutor@3f197a46
MySecondPlugin...plugin:org.apache.ibatis.executor.CachingExecutor@3f197a46
DEBUG 05-27 18:24:17,428 Cache Hit Ratio [com.ming.dao.EmployeeMapper]: 0.0  (LoggingCache.java:62) 
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.scripting.defaults.DefaultParameterHandler@5b239d7d
MySecondPlugin...plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@5b239d7d
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.resultset.DefaultResultSetHandler@6d763516
MySecondPlugin...plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@6d763516
MyPlugin...四大对象创建的时候被调用....plugin:Mybatis将要包装的对象org.apache.ibatis.executor.statement.RoutingStatementHandler@37afeb11
MySecondPlugin...plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@37afeb11
DEBUG 05-27 18:24:17,432 ==>  Preparing: select id,last_name AS lastName,gender,email from tbl_employee WHERE id = ?   (BaseJdbcLogger.java:145) 
MySecondPlugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
MyPlugin....intercept:自定义插件拦截的目标方法public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
拦截到的目标对象:org.apache.ibatis.executor.statement.RoutingStatementHandler@37afeb11
sql语句用的参数是:{id=1, param1=1}
DEBUG 05-27 18:24:17,446 ==> Parameters: 5(String)  (BaseJdbcLogger.java:145) 
DEBUG 05-27 18:24:17,455 <==      Total: 1  (BaseJdbcLogger.java:145) 
Employee{id=5, lastName='李四', email='[email protected]', gender='男', userList=null}
DEBUG 05-27 18:24:17,456 put added 0 on heap  (Segment.java:425) 

三、扩展分页插件

1、PageHelper插件进行分页

PageHelper是MyBatis中非常方便的第三方分页插件

分页插件官方文档

使用步骤

1.引入依赖

		<dependency>
		    <groupId>com.github.pagehelper</groupId
		    <artifactId>pagehelper</artifactId>
		    <version>5.1.10</version>
			</dependency>
		<!-- pagehelper 依赖 -->
		<dependency>
		    <groupId>com.github.jsqlparser</groupId>
		    <artifactId>jsqlparser</artifactId>
		    <version>2.1</version>
		</dependency>
		
		<dependency>
	        <groupId>com.baomidou</groupId>
	        <artifactId>mybatis-plus-boot-starter</artifactId>
	    </dependency>

2、在MyBatis全局配置文件中配置分页插件

    <plugins>
        <plugin interceptor="com.ming.plugin.MyPlugin">
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </plugin>
        <plugin interceptor="com.ming.plugin.MySecondPlugin">
        </plugin>
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
            <property name="param1" value="value1"/>
        </plugin>
    </plugins>

3、使用PageHelper提供的方法进行分页

	@Test
	public void test01() throws IOException {
		// 1、获取sqlSessionFactory对象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 2、获取sqlSession对象
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			Page<Object> page = PageHelper.startPage(5, 1);
			
			List<Employee> emps = mapper.getEmps();
			//传入要连续显示多少页
			PageInfo<Employee> info = new PageInfo<>(emps, 5);
			for (Employee employee : emps) {
				System.out.println(employee);
			}
			/*System.out.println("当前页码:"+page.getPageNum());
			System.out.println("总记录数:"+page.getTotal());
			System.out.println("每页的记录数:"+page.getPageSize());
			System.out.println("总页码:"+page.getPages());*/
			///xxx
			System.out.println("当前页码:"+info.getPageNum());
			System.out.println("总记录数:"+info.getTotal());
			System.out.println("每页的记录数:"+info.getPageSize());
			System.out.println("总页码:"+info.getPages());
			System.out.println("是否第一页:"+info.isIsFirstPage());
			System.out.println("连续显示的页码:");
			int[] nums = info.getNavigatepageNums();
			for (int i = 0; i < nums.length; i++) {
				System.out.println(nums[i]);
			}
			
		} finally {
			openSession.close();
		}

	}
	

4、可以使用更强大的PageInfo封装返回结果

2、批量操作

第一种:ExecutorType.BATCH

    @Test
    public  void addBatchEmp() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //可以执行批量操作的sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        try {
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            for (int i = 0; i < 1000; i++) {
                Employee employee = new Employee();
                employee.setLastName(UUID.randomUUID().toString().substring(0,5));
                employee.setEmail("[email protected]");
                employee.setGender("男");
                employeeMapper.addEmps(employee);
            }
            sqlSession.commit();
        }finally {
            sqlSession.close();
        }
    }

第二种: 与Spring整合中,我们推荐,额外的配置一个可以专门用来执行批量操作的sqlSession
配置一个可以执行批量执行的sqlSession,并注入Sqlsession

    <!--3.spring整合mybatis-->
    <bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--指定mybatis全局文件的位置-->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
        <!--指定mybatis的mapper文件位置,如果mapper和xml在同一个目录可以不用配置-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
    <!--配置一个可以执行批量执行的sqlSession-->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="SqlSessionFactory"/>
        <constructor-arg name="executorType" value="BATCH"/>
    </bean>

测试

    @Autowired
    SqlSession sqlSession;

    @Test
    public void mapperCrud() {
        //批量插入利用SqlSessionTemplate
        for (int i=0;i<1000;i++){
           String uuid= UUID.randomUUID().toString().substring(0,5)+i;
           EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
           empMapper.insertSelective(new Emp(null,uuid,"m",uuid+"@qq.com",1));
        }

    }

需要用到批量操作的时候,我们可以注入配置的这个批量SqlSession。通过他获取到mapper映射器进行操作。

注意:
1、批量操作是在session.commit()以后才发送sql语句给数据库进行执行的

2、如果我们想让其提前执行,以方便后续可能的查询操作获取数据,我们可以使用sqlSession.flushStatements()方法,让其直接冲刷到数据库进行执行。

三、存储过程

一、创建
create procedure 存储过程名(参数模式 参数名 参数类型)
begin
存储过程体
end
注意:
1.参数模式:in、out、inout,其中in可以省略
2.存储过程体的每一条sql语句都需要用分号结尾

二、调用
call 存储过程名(实参列表)
举例:
调用in模式的参数:call sp1(‘值’);
调用out模式的参数:set @name; call sp1(@name);select @name;
调用inout模式的参数:set @name=值; call sp1(@name); select @name;
三、查看
show create procedure 存储过程名;
四、删除
drop procedure 存储过程名;

MyBatis系列第九篇:MyBatis插件_第3张图片

	<!-- public void getPageByProcedure(); 
	1、使用select标签定义调用存储过程
	2、statementType="CALLABLE":表示要调用存储过程
	3{call procedure_name(params)}
	-->
	<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
		{call hello_test(
			#{start,mode=IN,jdbcType=INTEGER},
			#{end,mode=IN,jdbcType=INTEGER},
			#{count,mode=OUT,jdbcType=INTEGER},
			#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
		)}
	</select>
	<resultMap type="com.atguigu.mybatis.bean.Employee" id="PageEmp">
		<id column="EMPLOYEE_ID" property="id"/>
		<result column="LAST_NAME" property="lastName"/>
		<result column="EMAIL" property="email"/>
	</resultMap>	

/**
 * 封装oracle分页
 */
public class Page {

    private Integer start;
    private Integer end;
    private List<Employee> employeeList;
}
	/**
	 * oracle分页:
	 * 		借助rownum:行号;子查询;
	 * 存储过程包装分页逻辑
	 * @throws IOException 
	 */
	@Test
	public void testProcedure() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			OraclePage page = new OraclePage();
			page.setStart(1);
			page.setEnd(5);
			mapper.getPageByProcedure(page);
			
			System.out.println("总记录数:"+page.getCount());
			System.out.println("查出的数据:"+page.getEmps().size());
			System.out.println("查出的数据:"+page.getEmps());
		}finally{
			openSession.close();
		}
		
	}

mysql_procedure:

create procedure mb_emps(in p_id int)

begin
        select * from tbl_employee WHERE id = p_id;
end;


show create procedure mb_emps;
    <!--  mysql储存过程调用
    1、使用select标签定义调用存储过程
    2、statementType="CALLABLE":表示要调用存储过程
    3{call procedure_name(params)}-->
   <!-- public List<Employee> getEmps(Integer id);-->
    <select id="getEmps" statementType="CALLABLE" resultMap="procedureEmp">
       {CALL mb_emps(#{userId,mode=IN,jdbcType=INTEGER})}
    </select>
    <resultMap id="procedureEmp" type="com.ming.po.Employee">
        <id property="id" column="id"></id>
        <result property="lastName" column="last_name" jdbcType="VARCHAR"/>
        <result property="email" column="email" jdbcType="VARCHAR"/>
        <result property="gender" column="gender" jdbcType="VARCHAR"/>
    </resultMap>
    @Test
    public void procedureTest() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            List<Employee> emps = employeeMapper.getEmps(1);
            System.out.println(emps);
        }finally {
            sqlSession.close();
        }
    }

四、自定义类型处理器

我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略。

步骤:
1、实现TypeHandler接口或者继承BaseTypeHandler

2、使用@MappedTypes定义处理的Java类型、使用@MappedJdbcTypes定义jdbcType类型

3、在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理或者在全局配置TypeHandler要处理的javaType

自定义类型处理器

package com.ming.typehandler;

import com.ming.po.EmpStatus;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 自定义类型处理器
 *
 * 实现TypeHandler或者继承BaseTypeHandler
 *
 */
public class MyTypeHandler implements TypeHandler<EmpStatus> {
     // 定义当前数据如何保存到数据库中
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, EmpStatus empStatus, JdbcType jdbcType) throws SQLException {
        System.out.println("数据库要保存的状态码:"+empStatus.getCode());
        preparedStatement.setString(i,empStatus.getCode().toString());
    }

    @Override
    public EmpStatus getResult(ResultSet resultSet, String s) throws SQLException {
        //根据从数据库中拿到枚举状态码返回枚举对象
        int code = resultSet.getInt(s);
        System.out.println("从数据库中获取的状态码:"+code);
        return EmpStatus.getEmpByCode(code);
    }

    @Override
    public EmpStatus getResult(ResultSet resultSet, int i) throws SQLException {
        //根据从数据库中拿到枚举状态码返回枚举对象
        int code = resultSet.getInt(i);
        System.out.println("从数据库中获取的状态码:"+code);
        return EmpStatus.getEmpByCode(code);
    }

    @Override
    public EmpStatus getResult(CallableStatement callableStatement, int i) throws SQLException {
        //根据从数据库中拿到枚举状态码返回枚举对象
        int code = callableStatement.getInt(i);
        System.out.println("从数据库中获取的状态码:"+code);
        return EmpStatus.getEmpByCode(code);
    }
}

mybatis-config.xml配置类型处理器

    <!--类型处理器-->
    <typeHandlers>
        <!--1、配置自定义的类型处理器-->
        <typeHandler handler="com.ming.typehandler.MyTypeHandler" javaType="com.ming.po.EmpStatus"/>
        <!--<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.ming.po.EmpStatus"/>-->
        <!--2、也可以在处理某个字段的时候告诉mybatis用什么类型处理器
        保存:在取值的时候设置类型处理器
        #{empStatus,TypeHandler=TypeHandler全限定类名(EnumOrdinalTypeHandler)}
        查询: <result property="empStatus" column="empStatus" typeHandler=""/>
        注意:如果在参数位置修改TypeHandler,应该保证保存数据和查询数据用的TypeHandler是一样的
        -->
    </typeHandlers>
package com.ming.po;

/**
 * 数据库保存状态码
 */
public enum EmpStatus {

    LOGIN(100,"用户登录"),LOGOUT(200,"用户登出"),REMOVE(300,"用户不存在");

    private EmpStatus(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private Integer code;
    private String msg;

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    //按照状态码返回枚举对象
    public static EmpStatus getEmpByCode(Integer code){
        switch (code){
            case 100:
                return LOGIN;
            case 200:
                return LOGOUT;
            case 300:
                return REMOVE;
            default:
                return LOGOUT;
        }
    }
    
}

你可能感兴趣的:(MyBatis,mybatis)