zoukankan      html  css  js  c++  java
  • mybatis学习系列五--插件及类型处理器

    2 插件编写(80-81

    单个插件编写

    2.1实现interceptor接口(ibatis

    invocation.proceed()方法执行必须要有,否则不会无法实现拦截作用

    2.2 使用@intercepts注解完成插件签名

    2.3 将插件注册到全局配置文件中<plugins>标签

    全局配置文件注册plugin时报错:

    The content of element type "configuration" must match

    "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".

    原因:configuration 中的元素不仅有类型限制,还有顺序限制

    https://blog.csdn.net/u011199063/article/details/78971527

    按照提示的顺序即可

    多个插件

    插件动态代理时,按插件配置顺序配置层层代理对象,执行目标方法时,按逆向顺序执行

    配置的插件顺序

    <!-- 自定义插件 -->

    <plugins>

    <plugin interceptor="com.mybatis.bean.MyPlugin">

    <!-- 配置插件属性,在插件setProperties方法中使用 -->

    <property name="username1" value="root1"/>

    <property name="password1" value="1"/>

    </plugin>

    <plugin interceptor="com.mybatis.bean.MySecondPlugin">

    <property name="username2" value="root2"/>

    <property name="password2" value="2"/>

    </plugin>

    </plugins>

    执行打印日志:

    22:29:05,207  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.SimpleExecutor@24b1d79b

    22:29:05,208  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.SimpleExecutor@24b1d79b

    22:29:05,239  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@70beb599

    22:29:05,239  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@70beb599

    22:29:05,242  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@365c30cc

    22:29:05,242  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@365c30cc

    22:29:05,243  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@4148db48

    22:29:05,243  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@4148db48

    显示包装顺序按配置顺序

    再看执行intercept方法执行顺序:

    22:29:05,272  INFO Class:40 - myfirstplugin intercept:null

    22:29:05,272  INFO Class:40 - mysecondplugin intercept:null

    也是按顺序执行,并不是如图所示的包装按正序,执行按逆序

    3 插件开发(82

    只有再插件类中intercept方法中调用invocation.proceed()方法才能执行拦截的目标方法

    简单开发:修改sql参数

    //获取拦截的对象

    Object target=invocation.getTarget();

    log.info(target);

    //获取target的元数据

    MetaObject metaObject=SystemMetaObject.forObject(target);

    Object value=metaObject.getValue("parameterHandler.parameterObject");

    System.out.println("sql语句的参数:"+value);

    //修改sql语句参数

    metaObject.setValue("parameterHandler.parameterObject", 3);

    //执行目标方法

    Object proceed = invocation.proceed();

    log.info("myfirstplugin intercept:"+proceed);

    执行后打印信息:

    sql语句的参数:2

    22:00:27,942 DEBUG getMyDeptById:145 - ==> Parameters: 3(Integer)

    可见,sql参数从2修改为3

    4 pagehelper分页插件(83

    引入:

    1pom配置

    <!-- pagehelper分页插件 -->    

    <dependency>

         <groupId>com.github.pagehelper</groupId>

         <artifactId>pagehelper</artifactId>

         <version>4.1.4</version>

      </dependency>

    2全局配置文件中配置

    mybatis-config.xml

    <plugins>

    <!-- 分页插件 -->

    <plugin interceptor="com.github.pagehelper.PageHelper">

            <property name="dialect" value="mysql"/>

            <property name="offsetAsPageNum" value="false"/>

            <property name="rowBoundsWithCount" value="false"/>

            <property name="pageSizeZero" value="true"/>

            <property name="reasonable" value="false"/>

            <property name="supportMethodsArguments" value="false"/>

            <property name="returnPageInfo" value="none"/>

        </plugin>

    </plugins>

    3 测试类

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    //获取页码信息方式1 (startPage方式)

    Page<Object> startPage = PageHelper.startPage(3, 3);

    List<Employee> emps=mapper.selectEmployeeByInnerParameter(null);

    // System.out.println("当前页码:"+startPage.getPageNum());

    // System.out.println("总记录数:"+startPage.getTotal());

    // System.out.println("每页记录数:"+startPage.getPageSize());

    // System.out.println("总页码:"+startPage.getPages());

    // System.out.println("分页后当前页码数据条数:"+emps.size());

    //获取页码信息方式2  (pageInfo信息更丰富)

    // PageInfo<Employee> pageInfo = new PageInfo<>(emps);

    //2个参数,后面参数表示分页导航,连续显示多少页码(即每次显示5页,如2,3,4,5,6)

    PageInfo<Employee> pageInfo = new PageInfo<>(emps,2);

    System.out.println("当前页码:"+pageInfo.getPageNum());

    System.out.println("总记录数:"+pageInfo.getTotal());

    System.out.println("每页记录数:"+pageInfo.getPageSize());

    System.out.println("总页码:"+pageInfo.getPages());

    System.out.println("分页后当前页码数据条数:"+emps.size());

    System.out.println("是否第一页:"+pageInfo.isIsFirstPage());

    System.out.println("连续显示页码:"+pageInfo.getNavigatePages());

    int[] navigatepageNums = pageInfo.getNavigatepageNums();

    for ( int i=0;i<navigatepageNums.length;i++) {

    System.out.println(navigatepageNums[i]);

    }

    输出结果:

    当前页码:3

    总记录数:11

    每页记录数:3

    总页码:4

    分页后当前页码数据条数:3

    是否第一页:false

    连续显示页码:2

    2

    3

    5 mybatis批量操作(84

    1采用batch方式进行批量插入操作:

    //batch类型的session

    SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);

    try {

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    long start=System.currentTimeMillis();

    for(int i=0;i<1000;i++) {

    mapper.addEmp(new Employee(null,"name_"+i, "email_"+i+"@com.cn", (i%2)+"", (i%2)));

    }

    session.commit();

    long end=System.currentTimeMillis();

    System.out.println("执行时间:"+(end-start));

    } finally {

      session.close();

    }

    执行效果:

    21:49:06,354 DEBUG addEmp:145 - ==> Parameters: name_304(String), email_304@com.cn(String), 0(String), 0(Integer)

    21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_305(String), email_305@com.cn(String), 1(String), 1(Integer)

    21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_306(String), email_306@com.cn(String), 0(String), 0(Integer)

    21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_307(String), email_307@com.cn(String), 1(String), 1(Integer)

    21:49:06,356 DEBUG addEmp:145 - ==> Parameters: name_308(String), email_308@com.cn(String), 0(String), 0(Integer)

    执行时间:

    21:49:07,208 DEBUG JdbcTransaction:69 - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6ebc05a6]

    执行时间:1198

    2非batch方式批量操作:

    //非batch批量操作session

    SqlSession session = sqlSessionFactory.openSession();

    try {

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    long start=System.currentTimeMillis();

    for(int i=0;i<1000;i++) {

    mapper.addEmp(new Employee(null,"name_"+i, "email_"+i+"@com.cn", (i%2)+"", (i%2)));

    }

    session.commit();

    long end=System.currentTimeMillis();

    System.out.println("执行时间:"+(end-start));

    } finally {

      session.close();

    }

    执行情况:

    21:52:44,356 DEBUG addEmp:145 - ==> Parameters: name_987(String), email_987@com.cn(String), 1(String), 1(Integer)

    21:52:44,356 DEBUG addEmp:145 - <==    Updates: 1

    21:52:44,356 DEBUG addEmp:145 - ==>  Preparing: insert into myemployeee(last_name,email,gender,dept_id) values (?,?, ?,?)

    21:52:44,356 DEBUG addEmp:145 - ==> Parameters: name_988(String), email_988@com.cn(String), 0(String), 0(Integer)

    21:52:44,357 DEBUG addEmp:145 - <==    Updates: 1

    执行时间:

    执行时间:1376

    原因:

    批量batch方式:(预编译sql一次==》设置参数==1000==

    非批量:(预编译sql==》设置参数==》执行)==1000

    执行次数

    非批量执行时间(ms)

    批量执行时间(ms)

    1000

    1376

    1198

    10000

    11649

    3607

    50000

    37831

    10593

    100000

    62868

    20195

    性能在3倍左右

    spring整合时,如果获取bathsqlsession

    配置带batchsqlsession并使用

     

    使用时引入:

     6mybatis存储过程(85-86

    可以理解为sql集合,复杂sql情况下

    Oracle中分页借助伪列(rowid)

    <=end,再>=start  (注意如果先>=start<=end会导致数据不确定而错误)

    1创建分页类:

    /**

     * 分页类

     * @author admin

     *

     */

    public class Page {

    private int start;

    private int end;

    private int count;

    private List<Employee> emps;

    public int getStart() {

    return start;

    }

    分页查询:先查询总记录数,再进行分页查询

    2/**创建oracle存储过程*/

    create or replace procedure

    hello_test(//存储过程名

    p_start in int,//p_start-->参数开始行;in-->表示输入;int表示参数类型

    p_end in int,//p_end-->参数结束行;in-->表示输入;int表示参数类型

    p_count out int,//输出

    p_emps out sys_refcursor//输出,游标

    ) as

    begin

    select count(*) into p_count from employee;//将查询的总记录数交给p_count

    open p_emps for //打开游标

    select * from

    (select rownum rn,e.* from employee e where rownum<=p_end)

    where rn>=p_start;

    end hello_test;

    3使用存储过程:

    3.1Select * from user_source;

    查看存储过程

    3.2mybatis调用存储过程

     

    1)定义查询接口

    //调用存储过程分页(参数为定义的page)

    void getPageByProcedure(Page page);

    2)mapper中定义查询存储过程的sql

    <!-- statementType="CALLABLE" 表示调用存储过程 -->

      <select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">

       <!-- 固定用法 { call 存储过程名(参数1,参数2,...) } -->

       {call

       hello_test(

       #{start,mode=IN,jdbcType=INTEGER},

       #{end,mode=IN,jdbcType=INTEGER},

       #{end,mode=IN,jdbcType=INTEGER},

       #{count,mode=OUT,jdbcType=INTEGER},

       #{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=resultMap}

       <!-- 游标处理,使用ResultSet封装结果集 -->

       ) }

      </select>

    3)调用测试

    //存储过程查询

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    Page page = new Page();

    page.setStart(1);

    page.setEnd(10);

    mapper.getPageByProcedure(page);

    System.out.println("总记录数:"+page.getCount());

    System.out.println("查出的数据:"+page.getEmps().size());

     

     

    7 mybatis存自定义类型处理器(87

    自定义typehandler处理枚举类型

    设置参数和处理结果时调用typehandler处理参数,将java类型和数据库类型映射。

    查看typehandler接口:

    public interface TypeHandler<T> {

      void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

      T getResult(ResultSet rs, String columnName) throws SQLException;

      T getResult(ResultSet rs, int columnIndex) throws SQLException;

      T getResult(CallableStatement cs, int columnIndex) throws SQLException;

    }

    初步使用枚举

    /**

     * 枚举工具类

     * @author admin

     *

     */

    public class EnumUtils {

    //雇员状态

    public enum EmployeeStaus{

    LOGIN,//登陆

    LONGOUT,//推出

    REMOVE//移除

    }

    //枚举测试

    public static void main(String[] args) {

    EmployeeStaus status=EmployeeStaus.LOGIN;

    System.out.println("枚举的索引:"+status.ordinal());

    System.out.println("枚举的名字:"+status.name());

    }

    }

    输出:

    枚举的索引:0

    枚举的名字:LOGIN

    即枚举有索引和名字,接下来测试mybatis默认存放的是什么

    1)myemployeee新增字段status

    -- 新增状态字段

    alter table myemployeee add column status varchar(11);

     

    2) bean对象添加对应属性

     

    private EmployeeStaus status=EmployeeStaus.LONGOUT;//状态枚举类型,默认退出状态

    并提供构造方法:

    public Employee(String lastName, String email, String gender, Integer deptId, MyDept myDept,

    EmployeeStaus status) {

    super();

    this.lastName = lastName;

    this.email = email;

    this.gender = gender;

    this.deptId = deptId;

    this.myDept = myDept;

    this.status = status;

    }

    3)mapper新增插入字段

    <insert id="addEmp" parameterType="com.mybatis.bean.Employee">

       insert into myemployeee(last_name,email,gender,dept_id,status)

    values (#{lastName,jdbcType=VARCHAR},#{email,jdbcType=VARCHAR},

       #{gender,jdbcType=VARCHAR},#{deptId,jdbcType=INTEGER},#{status})

      </insert>

     

    4测试插入:

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    mapper.addEmp(new Employee("test11", "test11@com.cn",

    1+"", 1, null, EmployeeStaus.LONGOUT));

    5)查看数据库存入数据

    select t.* from myemployeee  t order by t.id desc limit 1;

     

    可以看到默认存储的是枚举的名字

     

    原因:

    默认使用enumTypehandler处理(包含EnumTypeHandlerEnumOrdinalTypeHandler2种类型)

    设置参数时代码如下:

     @Override

      public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {

        if (jdbcType == null) {

          ps.setString(i, parameter.name());

        } else {

          ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589

        }

      }

    可见保存的是枚举的名字。

    变更处理器

    可以改变使用EnumOrdinalTypeHandler

    在全局配置器中设置:

     <!-- 处理指定enum类型,不指定则处理所有enum类型 -->

      <typeHandlers>

       <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.mybatis.bean.EnumUtils.EmployeeStaus"/>

      </typeHandlers>

     

    执行报错:

    ## The error may exist in SQL Mapper Configuration

    ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)

    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)

    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)

    at com.mybatis.bean.Mytest_eum_test.getSqlSessionFactory(Mytest_eum_test.java:45)

    at com.mybatis.bean.Mytest_eum_test.main(Mytest_eum_test.java:29)

    Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:120)

    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98)

    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78)

    ... 3 more

    Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

    at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:118)

    at org.apache.ibatis.builder.xml.XMLConfigBuilder.typeHandlerElement(XMLConfigBuilder.java:337)

    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:117)

    ... 5 more

    Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

    at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:120)

    at org.apache.ibatis.builder.BaseBuilder.resolveAlias(BaseBuilder.java:149)

    at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:116)

    ... 7 more

    Caused by: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

    at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:200)

    at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89)

    at org.apache.ibatis.io.Resources.classForName(Resources.java:261)

    at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:116)

    使用另一种方式(不在全局配置中配置,仅在执行处指定)

     <insert id="addEmp" parameterType="com.mybatis.bean.Employee">

       insert into myemployeee(last_name,email,gender,dept_id,status)

    values (#{lastName,jdbcType=VARCHAR},#{email,jdbcType=VARCHAR},

       #{gender,jdbcType=VARCHAR},#{deptId,jdbcType=INTEGER},#{status,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler})

      </insert>

    测试:

    EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

    mapper.addEmp(new Employee("test22", "test22@com.cn",

    1+"", 1, null, EmployeeStaus.LONGOUT));

    session.commit();

    查看数据库:

  • 相关阅读:
    poj 3613(经过N条边的最短路)
    poj 3328(多起点多终点的最短路)
    poj 3311(floyd+状态压缩)
    新CCIE笔记-IP网络基础
    新CCIE笔记-IP网络基础
    算法之【冒泡排序法】
    算法之【冒泡排序法】
    算法之【冒泡排序法】
    算法之【辗转相除法】
    算法之【辗转相除法】
  • 原文地址:https://www.cnblogs.com/cslj2013/p/10507814.html
Copyright © 2011-2022 走看看