Mybatis学习笔记二

1. Mybatis逆向工程

1.1 说明

  1. MyBatis Generator官方文档地址

  2. 官方工程地址

  3. 依赖的包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--mybatis逆向工程依赖包-->
    <dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.4.0</version>
    </dependency>
    <dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.4.0</version>
    </dependency>

    1.2 逆向功能的配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
    PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>

    <!--
    targetRuntime="MyBatis3Simple":生成简单版的CRUD
    MyBatis3:豪华版

    -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
    <!-- jdbcConnection:指定如何连接到目标数据库 -->
    <jdbcConnection driverClass="com.mysql.jdbc.Driver"
    connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
    userId="root"
    password="123456">
    </jdbcConnection>

    <!-- -->
    <javaTypeResolver >
    <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>

    <!-- javaModelGenerator:指定javaBean的生成策略
    targetPackage="test.model":目标包名
    targetProject="\MBGTestProject\src":目标工程
    -->
    <javaModelGenerator targetPackage="com.atguigu.mybatis.bean"
    targetProject=".\src">
    <property name="enableSubPackages" value="true" />
    <property name="trimStrings" value="true" />
    </javaModelGenerator>

    <!-- sqlMapGenerator:sql映射生成策略: -->
    <sqlMapGenerator targetPackage="com.atguigu.mybatis.dao"
    targetProject=".\conf">
    <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>

    <!-- javaClientGenerator:指定mapper接口所在的位置 -->
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.dao"
    targetProject=".\src">
    <property name="enableSubPackages" value="true" />
    </javaClientGenerator>

    <!-- 指定要逆向分析哪些表:根据表要创建javaBean -->
    <table tableName="tbl_dept" domainObjectName="Department"></table>
    <table tableName="tbl_employee" domainObjectName="Employee"></table>
    </context>
    </generatorConfiguration>

2. Mybatis的运行原理

运行原理图
框架原理图

2.1 sqlsessionFactory的初始化

  1. 根据配置文件创建sqlsessionFactory
  2. 几个重要的类






    缓存中保存的key:方法id+sql+参数xxx

2.2 openSession获取SqlSession对象

返回SqlSession的实现类DefaultSqlSession对象。他里面包含了Executor和Configuration;Executor会在这一步被创建

2.3 getMapper获取到接口的代理对象

getMapper返回接口的代理对象包含了SqlSession对象

2.4 查询实现

3.插件

MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。
MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。
默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

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

3.1 插件开发的步骤

  1. 编写插件实现Interceptor接口并使用@Intercepts注解完成插件签名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    package com.atguigu.in;

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

    import java.util.Properties;

    /**
    * intercept:拦截目标对象的目标方法的执行
    * 完成插件的签名:
    * 告诉mybatis当前插件来拦截那个执行器的那个方法
    */
    @Intercepts({
    @Signature(
    type = StatementHandler.class,method = "parameterize",args=java.sql.Statement.class
    )
    })
    public class MyFirstIn implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    //放行执行目标方法
    Object proceed = invocation.proceed();
    return proceed;
    }

    /**
    * 插件包装
    * 为目标对象创建一个代理对象
    * @param target
    * @return
    */
    @Override
    public Object plugin(Object target) {
    Object wrap = Plugin.wrap(target, this);
    //我们可以借助Plugin的wrap方法来使用当前的拦截器包装我们的对象
    //返回为当前target创建的动态代理
    return wrap;
    }

    /**
    * 将插件注册时的properties属性注册出来
    * @param properties
    */
    @Override
    public void setProperties(Properties properties) {
    System.out.println("可以拿到插件的信息");
    }
    }
  2. 在全局配置文件中注册插件

    1
    2
    3
    4
    5
    <plugins>
    <plugin interceptor="com.atguigu.in.MyFirstIn">
    <property name="name" value="ceshi"/>
    </plugin>
    </plugins>

4. mybatis批量操作

  • 默认的openSession() 方法没有参数,它会创建有如下特性的

    • 会开启一个事务(也就是不自动提交)
    • 连接对象会从由活动环境配置的数据源实例得到
    • 事务隔离级别将会使用驱动或数据源的默认设置
    • 预处理语句不会被复用,也不会批量处理更
  • openSession 方法的ExecutorType类型的参数,枚举类型:

    • ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情(这是默认装配的)。它为每个语句的执行创建一个新的预处理语句
    • ExecutorType.REUSE: 这个执行器类型会复用预处理语句
    • ExecutorType.BATCH: 这个执行器会批量执行所有更新语句
  • 批量操作我们是使用MyBatis提供的BatchExecutor进行的,他的底层就是通过jdbc攒sql的方式进行的。我们可以让他攒够一定数量后发给数据库一次

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        publicvoidtest01() {
    SqlSession openSession = build.openSession(ExecutorType.BATCH);
    UserDao mapper = openSession.getMapper(UserDao.class);
    longstart = System.currentTimeMillis();
    for(inti = 0; i < 1000000; i++) {
    String name = UUID.randomUUID().toString().substring(0, 5);
    mapper.addUser(newUser(null, name, 13));
    }
    openSession.commit();
    openSession.close();
    longend = System.currentTimeMillis();
    System.out.println("耗时时间:"+(end-start));
    }
  • 与Spring整合中,我们推荐,额外的配置一个可以专门用来执行批量操作的sqlSession

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

注意

  1. 批量操作是在session.commit()以后才发送sql语句给数据库进行执行的
  2. 如果我们想让其提前执行,以方便后续可能的查询操作获取数据,我们可以使用sqlSession.flushStatements()方法,让其直接冲刷到数据库进行执行

5. 一个带游标的存储过程

  • MyBatis对存储过程的游标提供了一个JdbcType=CURSOR的支持,可以智能的把游标读取到的数据,映射到我们声明的结果集中

  • 存储过程的调用

    • select标签中statementType=“CALLABLE”

    • 标签体中调用语法:{call procedure_name(#{param1_info},#{param2_info})}

6.自定义TypeHandler处理枚举

  • 我们可以通过自定义TypeHandler的形式来在设置参数或者取出结果集的时候自定义参数封装策略
  • 步骤
    • 实现TypeHandler接口或者继承BaseTypeHandler
    • 使用@MappedTypes定义处理的java类型
    • 使用@MappedJdbcTypes定义jdbcType类型
    • 在自定义结果集标签或者参数处理的时候声明使用自定义TypeHandler进行处理,或者在全局配置TypeHandler要处理的javaType