MyBatis

64 阅读5分钟

MyBatis概述

  • ORM(Object Relational Mapping)持久层框架的佼佼者
  • 真正实现了SQL语句与Java代码的分离
  • 优秀的功能 动态SQL, 缓存, 插件-pageHelper等

Mybatis入参处理

  • 单参数Mybatis不做特殊处理, 直接取出参数赋值给xml文件, 如:#{id}, 当传递的为单参数的时候#{xxx}, Mybatis不会关心名称.
  • 多参数
    • 默认传递为多参数的时候, Mybatis会将参数起名为: arg0, arg1, param1, param2
    • JavaBean传递参数
      • 如果多个参数是业务逻辑的数据模型, 那么可以直接传入pojo
      • Xml文件中直接通过#{属性名}取出对应的值
    • Map接口
      • 如果参数个数比较少, 而且没有对应的Javabea n, 可以封装成Map
      • Xml文件中: #{key}取出map中对应的值
    • 注解@param
      public Person getPersonInfo(@Param("username") String username, @Param("id") Integer id);
      
      如果多个参数只使用了一个@Param, 那么Mybatis会自动启用默认的规则, 即第二个参数为Param1
  • 集合类型参数处理
    • 当参数为Collection接口, 转换为Map, Mapkeycollection
    public Person getPersonByCollection(Collection list);
    
    <select id="getPersonByCollection" resultType="person">
        select * from person where id=#{list[0]}
    </select>
    
    • 如果参数类型为List接口, 除了collection以外, list也可以作为key
    public Person getPersonByCollection(List list);
    
    <select id="getPersonByCollection" resultType="person">
        select * from person where id=#{list[0]}
    </select>
    
    • 如果参数为数组, 也会转换为Map, Mapkeyarray
    public Person getPersonByArray(int[] ids);
    
    <select id="getPersonByArray" resultType="person">
        select * from person where id=#{array[0]}
    </select>
    
    • 以上均可以使用param来处理
    public Person getPersonByArray(@Param("idsc") int[] ids);
    
    <select id="getPersonByArray" resultType="person">
        select * from person where id=#{idsc[0]}
    </select>
    
  • Mybatis动态SQLforeach
    • 特点 循环遍历集合, 支持数组和List, Set接口, 对其提供遍历功能
    • 常用配置
      • collection: 需要遍历的集合
      • item: 当前集合的对象
      • index: 当前遍历的对象的索引
      • openclose: 当前打开和关闭的字符串
      • separator: 每个元素的分割符
    • 代码示例
    // 根据传入的id的数组, 查询id在数组里的用户, 返回一个List列表
    <select id="getPersonListByIds" resultType="person">
        select * from person where id in
        <foreach collection="array" item="item" index="i" open="(" close=")"  separator=",">
            #{item}
        </foreach>
    </select>
    

Mybatis批量插入数据

  • 借助foreach标签使用insert into table values()
 // 根据传入的id的数组, 查询id在数组里的用户, 返回一个List列表
 <insert id="addPersons">
     insert into person(username, email, gender) values
     <foreach collection="persons" item="item" index="i"   separator=",">
         (#{item.username}, #{item.email}, #{item.gender})
     </foreach>
 </insert >
  • 借助ExecutorBatch批量添加, 可与Spring框架整合

Mybatis拦截器与分页

  • Mybatis四大对象
    • ParamterHandler: 处理SQL的参数对象
    • ResultSetHandler: 处理SQL的返回结果集
    • StatementHandler: 数据库的处理对象, 用于执行SQL
    • Executor: Mybatis的执行器, 用于执行增删改查
  • Mybatis插件原理
    • Mybatis的插件借助于责任链的模式进行对拦截的处理
    • 使用动态代理对目标对象进行包装, 达到拦截的目的
    • 作用于Mybatis的作用于对象之上
  • Interceptor
// 拦截目标对象的目标方法
public Object intercept(Invocation invocation) throws Throwable {
    System.out.println("拦截的目标对象" + invocation.getTarget());
    Object object = invocation.proceed();
    return object;
}
// 包装目标对象, 为目标对象创建代理对象的
public Object plugin(Object o) {
    System.out.println("将要包装的目标对象" + o);
    return Plugin.wrap(o, this);
}
// 设置属性, 在配置文件中声明拦截器, 初始化的属性
public void setProperties(Properties properties) {
      System.out.println("插件配置的初始化参数" + properties);
}
  • 分页
    • 分页的分类: 内存分页和物理分页
    • Mysql自带的Limit关键字
  • PageHelper
// 获取第一页 数量为10个
Page<Object> page = PageHelper.startPage(1, 10);
// 从数据库进行查询
List<Person> persons = personMapper.getAllPersons();
// 获取导航页面, 经常用于页面底部显示导航123....10页
PageInfo pageInfo = new PageInfo(persons, navigatePages: 9)

page.getPageNum(); // 获取当前的页面
page.getTotal(); // 获取总共多少页
page.getPageSize; // 获取一页有多少数量

pageInfo.isIsFirstPage(); // 是否是第一页
pageInfo.getPages(); // 总共多少页
// PageInfo pageInfo = new PageInfo(persons, navigatePages: 9) 输出nums为1, 2, 3,4,5,6,7,8,9
int [] nums = pageInfo.getNavigatepageNums(); // 获取页面

  • Mybatis分页应用
public ServerResponse getProductList(int pageNum, int pageSize) {
        // mybatis pageHelper的使用
        // 1. startPage->start
        PageHelper.startPage(pageNum, pageSize);
        // 2. 填充sql查询逻辑
        List<Product> productList = productMapper.selectProductList();
        List<ProductListVo> productListVos = new ArrayList<ProductListVo>();
        for (Product product : productList) {
            ProductListVo productListVo = assembleProduct(product);
            productListVos.add(productListVo);
        }
        // 3. pageHelper->收尾
        PageInfo pageResult = new PageInfo(productList);
        pageResult.setList(productListVos);
        return ServerResponse.createBySuccess(pageResult);
    }

Mybaitis自动生成Mapper映射文件和dao层实体类

1. 在pom.xml文件里新增Mybatis的generator

  <build>
    <finalName>项目名</finalName>
    <plugins>
      <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
          <verbose>true</verbose>
          <overwrite>true</overwrite>
        </configuration>
      </plugin>
    </build>

2.在resources包下面添加generator.properties和generatorConfig.xml, 其中generator.properties是数据库配置文件

generator.properties
db.initialSize = 20
db.maxActive = 50
db.maxIdle = 20
db.minIdle = 10
db.maxWait = 10
db.defaultAutoCommit = true
db.minEvictableIdleTimeMillis = 3600000

db.driverLocation=/Volumes/ruirui/mysql-connector/mysql-connector-java-5.0
 .8-bin.jar // 不能有中文路径
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/bos?characterEncoding=utf-8
db.username=root
db.password=root
generatorConfig.xml
<?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>
    <!--导入属性配置-->
    <properties resource="generator.properties"/>

    <!--指定特定数据库的jdbc驱动jar包的位置-->
    <classPathEntry location="${db.driverLocation}"/>

    <context id="default" targetRuntime="MyBatis3">

        <!-- optional,旨在创建class时,对注释进行控制 -->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!--jdbc的数据库连接 -->
        <jdbcConnection
                driverClass="${db.driverClassName}"
                connectionURL="${db.url}"
                userId="${db.username}"
                password="${db.password}">
        </jdbcConnection>


        <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>


        <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
            targetPackage     指定生成的model生成所在的包名
            targetProject     指定在该项目下所在的路径
        -->
        <!--<javaModelGenerator targetPackage="com.mmall.pojo" targetProject=".\src\main\java">-->
        <javaModelGenerator targetPackage="com.mmall.pojo" targetProject="./src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对model添加 构造函数 -->
            <property name="constructorBased" value="true"/>
            <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
            <property name="trimStrings" value="true"/>
            <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>

        <!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
        <!--<sqlMapGenerator targetPackage="mappers" targetProject=".\src\main\resources">-->
        <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
                type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
                type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
                type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
        -->

        <!-- targetPackage:mapper接口dao生成的位置 -->
        <!--<javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject=".\src\main\java">-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.mmall.dao" targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>


        <!-- tableName:数据库表名 -->
        <!-- domainObjectName:对应于数据库表的javaBean类名即pojo -->
        <!-- columnOverride :重新设置该属性, 在本案例中, 设置格式为VARCHAR; -->
        <table tableName="mmall_product" domainObjectName="Product" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
            <columnOverride column="detail" jdbcType="VARCHAR" />
            <columnOverride column="sub_images" jdbcType="VARCHAR" />
        </table>
        <table tableName="mmall_user" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" />
    </context>
</generatorConfiguration>

3. 自动生成

点击左边栏的Maven, 如果没有点击View=>Tool Window=> Maven Mybatis自动生成

有一个哥们私聊我, 在项目进行到一半, 如何自动生成新的pojo和mapper, 只需要将其他的注释掉, 仅保留需要生成的部分代码即可.

MyBatis工作原理与工作流程

MyBatis工作原理与工作流程

  • sql语句和数据库配置信息保存在配置文件中
  • Mybatis运行的时候, 将配置信息存储在Configuration对象里
  • 在创建SqlSession对象提供属性
    • Configuration对象
    • dirty: true sql语句执行完毕以后 可以事务提交 false sql语句执行发送错误 事务进行回滚
    • Executor执行器对象:
      • 创建Statement对象,在创建过程中依靠MapperStatement对象赋值内容与sql占位符进行绑定
  • SqlSession.commit(): 根据此时dirty属性决定提交和回滚
  • SqlSession.close()