MyBatis随记

 

MyBatis  

一、什么是MyBatis

  1、简介

  MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。

  MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

  对jdbc的封装框架有哪些:Hibernate,dbutils,jdbcTemplate[spring],mybatis

  原理:Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

  每一个 MyBatis 的应 用程序 都以一 个 SqlSessionFactory 对象的 实例为 核心。 SqlSessionFactory 对 象 的 实 例 可 以 通 过 SqlSessionFactoryBuilder 对 象 来 获 得 。 SqlSessionFactoryBuilder 对象可以通过 XML 配置文件,或从以往使用惯例中准备好的 Configuration 类实例中来构建 SqlSessionFactory 对象。 

 

  2、入门——从XML中构建SQLSessionFactory   

1、接口式编程
    原生:        Dao        ====>  DaoImpl
    mybatis:    Mapper    ====>  xxMapper.xml
2、SqlSession代表和数据库的一次会话;用完必须关闭;
3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。
4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
        (将接口和xml进行绑定)
        EmployeeMapper empMapper =    sqlSession.getMapper(EmployeeMapper.class);
5、两个重要的配置文件:
        mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
        sql映射文件:保存了每一个sql语句的映射信息:    将sql抽取出来。

步骤:
* 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息
* 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。
* 3、将sql映射文件注册在全局配置文件中
* 4、写代码:
* 1)、根据全局配置文件得到SqlSessionFactory;
* 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查
* 一个sqlSession就是代表和数据库的一次会话,用完关闭
* 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。

  2.1  从 XML 文件中构建 SqlSessionFactory 的实例非常简单。这里建议你使用类路径下的资 源文件来配置,但是你可以使用任意的 Reader 实例,这个实例包括由文字形式的文件路径 或 URL 形式的文件路径 file://来创建。MyBatis 包含了一些工具类,称作为资源,这些工具 类包含一些方法,这些方法使得从类路径或其它位置加载资源文件更加简单。 

1 //获取SqlSessionFactory
2     public SqlSessionFactory getSqlSessionFactory() throws IOException {
3         //读取配置文件
4         String resource = "mybatis-config.xml";
5         Reader reader = Resources.getResourceAsReader(resource);
6         return new SqlSessionFactoryBuilder().build(reader);
7     }

  mybatis-config.xml:

<?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>
    <!--
        1、mybatis可以使用properties来引入外部properties配置文件的内容;
        resource:引入类路径下的资源
        url:引入网络路径或者磁盘路径下的资源
      -->
    <properties resource="db.properties"/>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClass}"/>
                <property name="url" value="${jdbc.jdbcUrl}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="com/ant/mybatis/UserMapper.xml"/>
    </mappers>
</configuration>
mybatis-config.xml

  2.2  获取sqlSession对象,执行增删改查方法

public void daoSession() throws IOException {
        //获取sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try{
            //获取接口的实现类 对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //mybatis会给自动的创建一个代理对象,代理对象去执行增删改查 方法
            User user = userMapper.findUserById(2);
            System.out.println(userMapper.getClass());
            System.out.println(user);
        }finally {
            sqlSession.close();
        }
    }

  User实例

package com.ant.mybatis;

public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
User.java

  UserMapper.xml

<?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">
<!--
    namespace:命名空间,定义为接口的全类名。如下:
    id:唯一标识,可写用 方法名作为唯一标识
    public User findUserById(Integer id);
-->
<mapper namespace="com.ant.mybatis.dao.UserMapper">
    <select id="findUserById" resultType="com.ant.mybatis.User">
      select * from user where id = #{id}
     </select>
</mapper>
UserMapper.xml

  dao层的接口类

1 package com.ant.mybatis.dao;
2 
3 import com.ant.mybatis.User;
4 
5 public interface UserMapper {
6   //根据id查询User
7     public User findUserById(Integer id);
8 }

  2.3  结果:

 

二、全局配置文件(mybatis-config.xml) 详解

  1、<setting>运行时行为设置

<!--
   settings包含很多重要的设置项        
      setting:用来设置每一个设置项 name:设置项名 value:设置项取值
--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>

 

  2、typeAliases别名处理器

<!-- typeAliases:别名处理器:可以为我们的java类型起别名。别名不区分大小写  -->
    <typeAliases>
        <!-- 1、typeAlias:为某个java类型起别名
                type:指定要起别名的类型全类名;默认别名就是类名小写;employee
                alias:指定新的别名
         -->
        <!-- <typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> -->

        <!-- 2、类很多的情况下,可以批量设置别名这个包下的每一个类 创建一个默认的别名,就是简单类名小写
                package:为某个包下的所有类批量起别名
                name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写),)
        -->
        <package name="com.atguigu.mybatis.bean"/>
    </typeAliases>
* 批量起别名的情况下,使用@Alias注解为某个类型指定新的别名

 

  3、typeHandlers-类型处理器

无论是 MyBatis 在预处理语句(PreparedStatement)中 设置一个参数时,还是从结果集中取出一个值时, 都会 用类型处理器将获取的值以合适的方式转换成 Java 类型。 

 

// MapperConfig.xml 
<typeHandlers>
     <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers> 

 

  4、日期类型的处理

   日期和时间的处理,JDK1.8以前一直是个头疼的 问题。我们通常使用JSR310规范领导者Stephen Colebourne创建的Joda-Time来操作。1.8已经实 现全部的JSR310规范了。

   日期时间处理上,我们可以使用MyBatis基于 JSR310(Date and Time API)编写的各种日期 时间类型处理器。

   MyBatis3.4以前的版本需要我们手动注册这些处 理器,以后的版本都是自动注册的。

       

 

  5、plugins插件

   插件是MyBatis提供的一个非常强大的机制,我们 可以通过插件来修改MyBatis的一些核心行为。插 件通过动态代理机制,可以介入四大对象的任何 一个方法的执行。

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

 

  6、environments-指定具体环境

  id:指定当前环境的唯一标识

  transactionManager、和dataSource都必须有

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      
<property name="..." value="..."/>
    
</transactionManager>
    
<dataSource type="POOLED">
      
<property name="driver" value="${driver}"/>
      
<property name="url" value="${url}"/>
      
<property name="username" value="${username}"/>
      
<property name="password" value="${password}"/>
    
</dataSource>
  
</environment>
</environments>

 

 

 

  transactionManager
  • type: JDBC | MANAGED | 自定义

    – JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数 据源得到的连接来管理事务范围。 JdbcTransactionFactory

    – MANAGED:不提交或回滚一个连接、让容器来管理 事务的整个生命周期(比如 JEE 应用服务器的上下 文)。 ManagedTransactionFactory

    – 自定义:实现TransactionFactory接口,type=全类名/ 别名
  dataSource
  • type: UNPOOLED | POOLED | JNDI | 自定义

    – UNPOOLED:不使用连接池, UnpooledDataSourceFactory

    – POOLED:使用连接池, PooledDataSourceFactory

    – JNDI: 在EJB 或应用服务器这类容器中查找指定的数 据源

    – 自定义:实现DataSourceFactory接口,定义数据源的 获取方式。
  • 实际开发中我们使用Spring管理数据源,并进行 事务控制的配置来覆盖上述配置

 

  7、environment-指定具体环境

   transactionManager:

  • type: JDBC | MANAGED | 自定义

  – JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数 据源得到的连接来管理事务范围。 JdbcTransactionFactory

  – MANAGED:不提交或回滚一个连接、让容器来管理 事务的整个生命周期(比如 JEE 应用服务器的上下 文)。 ManagedTransactionFactory

  – 自定义:实现TransactionFactory接口,type=全类名/ 别名

  dataSource:
  • type: UNPOOLED | POOLED | JNDI | 自定义

  – UNPOOLED:不使用连接池, UnpooledDataSourceFactory

  – POOLED:使用连接池, PooledDataSourceFactory

  – JNDI: 在EJB 或应用服务器这类容器中查找指定的数 据源

  – 自定义:实现DataSourceFactory接口,定义数据源的 获取方式。
• 实际开发中我们使用Spring管理数据源,并进行 事务控制的配置来覆盖上述配置

 

 

   8、databaseIdProvider环境

   MyBatis 可以根据不同的数据库厂商执行不同的语句。

  • Type: DB_VENDOR

    – 使用MyBatis提供的VendorDatabaseIdProvider解析数据库 厂商标识。也可以实现DatabaseIdProvider接口来自定义。

  • Property-name:数据库厂商标识

  • Property-value:为标识起一个别名,方便SQL语句使用 databaseId属性引用

  • DB_VENDOR

    – 会通过 DatabaseMetaData  #getDatabaseProductName() 返回的字符 串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不 同版本会返回不同的值,所以最好通过设置属性别名来使其变短
  • MyBatis匹配规则如下:

    – 1、如果没有配置databaseIdProvider标签,那么databaseId=null

    – 2、如果配置了databaseIdProvider标签,使用标签配置的name去匹 配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为 null

    – 3、如果databaseId不为null,他只会找到配置databaseId的sql语句

    – 4、MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。

  

三、SQL映射配置文件(xxx-Mapper.xml)

  既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。 但是,首先我们需要告诉 MyBatis 到哪里去找到这些语句。Java 在这方面没有提供一个很好 的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的 资源引用,或者字符表示,或 url 引用的完全限定名(包括 file:///URLs)。

  1、mapper映射

  mapper逐个注册SQL映射文件

// 使用相对于类路径的资源 
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
// 使用完全限定路径
<mappers>
  <mapper url="file:///var/sqlmaps/AuthorMapper.xml"/>
  <mapper url="file:///var/sqlmaps/BlogMapper.xml"/>
  <mapper url="file:///var/sqlmaps/PostMapper.xml"/>
</mappers>

 

  或者使用批量注册: • 这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下

 

  2、MyBatis-映射文件

  •cache   –命名空间的二级缓存配置

  •cache-ref   – 其他命名空间缓存配置的引用。

  •resultMap   – 自定义结果集映射

  •parameterMap   – 已废弃!老式风格的参数映射

  •sql   –抽取可重用语句块。

  •insert   – 映射插入语句

  •update  – 映射更新语句

  •delete   – 映射删除语句

  •select   – 映射查询语句

   

  3、insert、update、delete元素

数据修改语句 insert,update 和 delete 在它们的实现中非常相似:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" useGeneratedKeys="" timeout="20000"> 
 
<update id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000"> 
 
<delete id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">

 

  

 

 

  4、主键生成方式

  若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上。

 

  而对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素: selectKey  元素将会首先运行,id  会被设置,然 后插入语句会被调用

 

 

  5、selectKey

  

  

  6、参数(Parameters)传递

     • 单个参数   – 可以接受基本类型,对象类型,集合类型的值。这种情况 MyBatis可直接使用这个参数,不需要经过任何处理。

  • 多个参数   – 任意多个参数,都会被MyBatis重新包装成一个Map传入。 Map的key是param1,param2,0,1…,值就是参数的值。

  • 命名参数   – 为参数使用@Param起一个名字,MyBatis就会将这些参数封 装进map中,key就是我们自己指定的名字

  • POJO   – 当这些参数属于我们业务POJO时,我们直接传递POJO

  • Map   – 我们也可以封装多个参数为map,直接传递

 

  7、参数处理

  a. 看源码,了解mybatis怎么处理参数:

 

总结:参数多时会封装map,为了不混乱,我们可以使用@Param来指定封装时使用的key;
#{key}就可以取出map中的值;

(@Param("id")Integer id,@Param("lastName")String lastName);
ParamNameResolver解析参数封装map的;
public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    //1、参数为null直接返回
    if (args == null || paramCount == 0) {
      return null;
     
    //2、如果只有一个元素,并且没有Param注解;args[0]:单个参数直接返回
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];
      
    //3、多个元素或者有Param标注
    } else {
      final Map<String, Object> param = new ParamMap<Object>();
      int i = 0;
      
      //4、遍历names集合;{0=id, 1=lastName,2=2}
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
      
          //names集合的value作为key;  names集合的key又作为取值的参考args[0]:args【1,"Tom"】:
          //eg:{id=args[0]:1,lastName=args[1]:Tom,2=args[2]}
        param.put(entry.getValue(), args[entry.getKey()]);
        
        
        // add generic param names (param1, param2, ...)param
        //额外的将每一个参数也保存到map中,使用新的key:param1...paramN
        //效果:有Param注解可以#{指定的key},或者#{param1}
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }
}

 

  b. 参数也可以指定一个特殊的数据类型:

  #{property,javaType=int,jdbcType=NUMERIC} 

  像 MyBatis 的剩余部分,javaType 通常可以从参数对象中来确定,除非对象是一个 HashMap。那么 javaType 应该被确定来保证使用正确类型处理器。

  对于数值类型,对于决定有多少数字是相关的,有一个数值范围。  #{height,javaType=double,jdbcType=NUMERIC,numericScale=2} 

 

  – javaType 通常可以从参数对象中来去确定:

    – 如果 null 被当作值来传递,对于所有可能为空的列, jdbcType 需要被设置

    – 对于数值类型,还可以设置小数点后保留的位数:

       – mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数 为 OUT 或 INOUT,参数对象属性的真实值将会被改变, 就像在获取输出参数时所期望的那样。  

 

  参数位置支持的属性 – javaType、jdbcType、mode、numericScale、 resultMap、typeHandler、jdbcTypeName、expression
  • 实际上通常被设置的是: 可能为空的列名指定 jdbcType

 

 

  • #{}:可以获取map中的值或者pojo对象属性的值;

  • ${}:可以获取map中的值或者pojo对象属性的值;

 

  区别:

    select * from tbl_employee where id=${id} and last_name=#{lastName}
    Preparing: select * from tbl_employee where id=2 and last_name=?
  #{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
  ${}:取出的值直接拼装在sql语句中;会有安全问题;
  大多情况下,我们去参数的值都应该去使用#{};

 

  eg:

    原生jdbc不支持占位符的地方我们就可以使用${}进行取值
    比如分表、排序。。。;按照年份分表拆分
    select * from ${year}_salary where xxx;
    select * from tbl_employee order by ${f_name} ${order}

 

 

  8、 select元素

  • Select元素来定义查询操作。

  • Id:唯一标识符。 – 用来引用这条语句,需要和接口的方法名一致

  • parameterType:参数类型。 – 可以不传,MyBatis会根据TypeHandler自动推断

  • resultType:返回值类型。 – 别名或者全类名,如果返回的是集合,定义集合中元 素的类型。不能和resultMap同时使用

      

select 元素有很多属性允许你配置,来决定每条语句的作用细节。
<select id=”selectPerson” parameterType=”int” 
     parameterMap=”deprecated” resultType=”hashmap”
     
resultMap=”personResultMap” flushCache=”false”
     
useCache=”true” timeout=”10000” fetchSize=”256”
     statementType=”PREPARED” resultSetType=”FORWARD_ONLY” >

  a. 查询 返回List集合

 

mapper.xml

  

   b. 查询返回Map

  返回一条记录的map:

 

resultType直接可以写map,以为mybatis已经为jdk起了别名。

  多条记录封装一个map:

//多条记录封装一个map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean
    //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
    @MapKey("lastName")
    public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
<!--public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName);  -->
     <select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee">
         select * from tbl_employee where last_name like #{lastName}
     </select>
Map<String, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%r%");
            System.out.println(map);

 

  9、自动映射

  • 1、全局setting设置

  – autoMappingBehavior默认是PARTIAL,开启自动映射 的功能。唯一的要求是列名和javaBean属性名一致

  – 如果autoMappingBehavior设置为null则会取消自动映射

  – 数据库字段命名规范,POJO属性符合驼峰命名法,如 A_COLUMNaColumn,我们可以开启自动驼峰命名规 则映射功能,mapUnderscoreToCamelCase=true。
  • 2、自定义resultMap,实现高级结果集映射。

 

  10、resultMap

  • constructor - 类在实例化时, 用来注入结果到构造方法中

    – idArg - ID 参数; 标记结果作为 ID 可以帮助提高整体效能

    – arg - 注入到构造方法的一个普通结果

  • id – 一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能

  • result – 注入到字段或 JavaBean 属性的普通结果

  • association

  – 一个复杂的类型关联;许多结果将包成这种类型

  – 嵌入结果映射 – 结果映射自身的关联,或者参考一个

  • collection

  – 复杂类型的集   – 嵌入结果映射   – 结果映射自身的集,或者参考一个

  • discriminator

  – 使用结果值来决定使用哪个结果映射

  – case – 基于某些值的结果映射

    • 嵌入结果映射   – 这种情形结果也映射它本身,因此可以包含很多相同的元 素,或者它可以参照一个外部的结果映射。

  自定义结果集映射规则: 

 

 

  关联查询-级联熟悉封装操作: 

 

  11、id & result

  • id 和 result 映射一个单独列的值到简单数据类型 (字符串,整型,双精度浮点数,日期等)的属性或字段。

 

  12、association

  • 复杂对象映射

  • POJO中的属性可能会是一个对象

  • 我们可以使用联合查询,并以级联属性的方式封 装对象。

  • 使用association标签定义对象的封装规则

  

  • association-嵌套结果集

 

 

  • association-分段查询

   select:调用目标的方法查询当前属性的值

  column:将指定列的值传入目标方法

 

 

  • association-分段查询&延迟加载

 

 

  • 开启延迟加载和属性按需加载

 

  在使用,调用到的时候 才去进行加载。

 

   13、Collection-集合类型&嵌套结果集

  

 

    collection:定义关联集合类型的属性的封装规则

    ofType:指定集合里面元素的类型

  

  

 

  Collection-分步查询&延迟加载

 

  14、分步查询传递多列值 和 fetchType

   扩展:多列的值传递过去:

    将多列的值封装map传递;
    column="{key1=column1,key2=column2}"
    fetchType="lazy":表示使用延迟加载;
      - lazy:延迟
      - eager:立即

  eg:

<collection property="emps" 
            select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
            column="{deptId=id}" fetchType="lazy"></collection>

 

  15、discriminator鉴别器

  <discriminator javaType=""></discriminator>
  鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
  封装Employee:
    如果查出的是女生:就把部门信息查询出来,否则不查询;
    如果是男生,把last_name这一列的值赋值给email;

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
         <id column="id" property="id"/>
         <result column="last_name" property="lastName"/>
         <result column="email" property="email"/>
         <result column="gender" property="gender"/>
         <!--
             column:指定判定的列名
             javaType:列值对应的java类型  -->
         <discriminator javaType="string" column="gender">
             <!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap-->
             <case value="0" resultType="com.atguigu.mybatis.bean.Employee">
                 <association property="dept" 
                     select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
                     column="d_id">
                 </association>
             </case>
             <!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
             <case value="1" resultType="com.atguigu.mybatis.bean.Employee">
                 <id column="id" property="id"/>
                 <result column="last_name" property="lastName"/>
                 <result column="last_name" property="email"/>
                 <result column="gender" property="gender"/>
             </case>
         </discriminator>
 </resultMap>

 

 四、MyBatis-动态SQL

  • 动态 SQL是MyBatis强大特性之一。极大的简化我们拼装 SQL的操作。

  • 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处 理器相似。

  • MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。

    – if    – choose (when, otherwise)     – trim (where, set)     – foreach

 

  1、if

  

  2、choose (when, otherwise)

  

  3、trim (where, set)

     

 

  

  在使用<if>时,当出现第一个条件不存在时,and连接符就出现多余的情况。这时候使用where。 

  where

  

  set

  

 

 

    后面多出的and或者or where标签不能解决 

    prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
    prefix给拼串后的整个字符串加一个前缀
    prefixOverrides="":
    前缀覆盖: 去掉整个字符串前面多余的字符
    suffix="":后缀
    suffix给拼串后的整个字符串加一个后缀
    suffixOverrides=""
    后缀覆盖:去掉整个字符串后面多余的字符

  trim

  

  4、foreach

  • 动态 SQL 的另外一个常用的必要操作是需要对一个集合 进行遍历,通常是在构建 IN 条件语句的时候。

  • 当迭代列表、集合等可迭代对象或者数组时   – index是当前迭代的次数,item的值是本次迭代获取的元素

  • 当使用字典(或者Map.Entry对象的集合)时   – index是键,item是值

  * foreach批量插入

  5、bind

  • bind 元素可以从 OGNL 表达式中创建一个变量并 将其绑定到上下文。比如:

  

  

五、MyBatis-缓存机制

   • MyBatis 包含一个非常强大的查询缓存特性,它可以非 常方便地配置和定制。缓存可以极大的提升查询效率。

  • MyBatis系统中默认定义了两级缓存。

  • 一级缓存和二级缓存。

    – 1、默认情况下,只有一级缓存(SqlSession级别的缓存, 也称为本地缓存)开启。

    – 2、二级缓存需要手动开启和配置,他是基于namespace级 别的缓存。

    – 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们 可以通过实现Cache接口来自定义二级缓存

 

  1、一级缓存

  • 一级缓存(local cache), 即本地缓存, 作用域默认 为sqlSession。当 Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。

  • 本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域. • 在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置

 

  * 一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的;SqlSession级别的一个Map

    * 与数据库同一次会话期间查询到的数据会放在本地缓存中。
    * 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;

  

  * 一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):
    * 1、sqlSession不同。

    * 2、sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)

    * 3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)

    * 4、sqlSession相同,手动清除了一级缓存(缓存清空)

 

 

  2、二级缓存

  • 二级缓存(second level cache),全局作用域缓存

  • 二级缓存默认不开启,需要手动配置

  • MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口

  • 二级缓存在 SqlSession 关闭或提交之后才会生效

  二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存:    * 工作机制:

      * 1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
      * 2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
      * 3、sqlSession===EmployeeMapper==>Employee
      * DepartmentMapper===>Department
      * 不同namespace查出的数据会放在自己对应的缓存中(map)
      * 效果:数据会从二级缓存中获取
      * 查出的数据都会被默认先放在一级缓存中。
      * 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
    * 使用:
      * 1)、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>

    

      * 2)、去mapper.xml中配置使用二级缓存:  <cache></cache>

    

    

      * 3)、我们的POJO需要实现序列化接口

    

  3、缓存相关属性

  • eviction=“FIFO”:缓存回收策略:

    • LRU – 最近最少使用的:移除最长时间不被使用的对象。

    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。   

    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    • 默认的是 LRU。

  • flushInterval:刷新间隔,单位毫秒   • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

  • size:引用数目,正整数   • 代表缓存最多可以存储多少个对象,太大容易导致内存溢出

  • readOnly:只读,true/false

    • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。

    • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是false。

 

 

  4、缓存有关设置

  • 1、全局setting的cacheEnable: – 配置二级缓存的开关。一级缓存一直是打开的。cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)

  • 2、select标签的useCache属性: – 配置这个select是否使用二级缓存。一级缓存一直是使用的

  

 

  • 3、sql标签的flushCache属性: – 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。 查询默认flushCache=false。

  

 

  • 4、sqlSession.clearCache(): – 只是用来清除一级缓存。

  • 5、当在某一个作用域 (一级缓存Session/二级缓存 Namespaces) 进行了 C/U/D 操作后,默认该作用域下所 有 select 中的缓存将被clear。

 

 

  5、第三方缓存整合 

  • EhCache 是一个纯Java的进程内缓存框架,具有快速、精 干等特点,是Hibernate中默认的CacheProvider。

  • MyBatis定义了Cache接口方便我们进行自定义扩展。

  • 步骤:

    – 1、导入ehcache包,以及整合包,日志包 ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar

    – 2、编写ehcache.xml配置文件   

 

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 <!-- 磁盘保存路径 -->
 <diskStore path="D:\44\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="10000" 
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>
 
<!-- 
属性说明:
     diskStore:指定数据在磁盘中的存储位置。
     defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
 
以下属性是必须的:
     maxElementsInMemory - 在内存中缓存的element的最大数目 
     maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
     eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
     overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
 
以下属性是可选的:
     timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
     timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
      diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
     diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
     diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
     memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
 -->

 

 

 

    – 3、配置cache标签 – <cache type= "org.mybatis.caches.ehcache.EhcacheCache"></cache>

  • 参照缓存:若想在命名空间中共享相同的缓存配置和实例。 可以使用 cache-ref 元素来引用另外一个缓存。

 

 

 

六、MyBatis-Spring整合

 

 

转载于:https://www.cnblogs.com/AntLiu/p/10938189.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值