Mybatis入门

这是学习颜群老师的mybatis教程后整理的笔记

Ⅰ、mybatis介绍与使用

1.mybatis是什么

MyBatis可以简化JDBC操作,实现数据的持久化

  • ORM的概念:Object Relational Mapping对象关系映射,例如person表对应一个person对象

    Mybatis是ORM的一个实现。有了mybatis,开发人员像操作对象一样操作数据库表

2.怎么用mybatis

  • 用maven

    
     org.mybatis
     mybatis
     x.x.x
    
    
  • 导入jar包,去官网下载(mybatis-x.x.x.jar)

3.第一次用mybatis操作数据库

构建路径/源路径:java代码在的路径

  • conf.xml:配置数据库信息和需要加载的映射文件,放在源路径下

    
    
    
        
       
             
           
            
              
               
               
               
               
               
               
           
           
       
       
          
          
       
    
    
    • dataSource标签的type属性:配置数据源类型
      • UNPOOLED:传统的JDBC模式(每次访问数据库、均需要打开、关闭数据库连接)
      • POOLED:使用数据库连接池
      • JNDI:从tomcat中获取一个内置的数据库连接池(数据库连接池--数据源)
    • environment标签的id属性:设置这个运行环境的id(测试、运行...)
    • environments标签的default的属性:填写当前运行需要的环境id值,与environment标签的id属性相对应
    • mapper标签的resource属性:数据库映射文件mapper.xml的相对路径
    • property标签:用于配置数据库连接字符串、用户名、密码、驱动等信息
    • transactionManager标签:用于设置事务方式
      • JDBC
      • MANAGER
  • personMapper.xml

    
    
    
      
      
      
          insert into person(id,name,age) values(#{id},#{name},#{age})
      
      
      
          delete from person where id = #{id}
      
      
      
          update person set name=#{name},age=#{age} where id=#{id}
      
      
      
    
    
    • mapper标签的namespace属性:放映射文件的路径,不用xml后缀

    • SQL语句类型的标识符

      • select
      • insert
      • delete
      • update

      以上四种标签中的id值来标识唯一一条SQL语句

  • 实体类Person

    package com.whl.entity;
    
    public class Person {
      private int id;
      private String name;
      private int age;
      
      public Person() {
    
      }
      public Person(int id, String name, int age) {
          this.id = id;
          this.name = name;
          this.age = age;
      }
      public int getId() {
          return id;
      }
      public void setId(int id) {
          this.id = id;
      }
      public String getName() {
          return name;
      }
      public void setName(String name) {
          this.name = name;
      }
      public int getAge() {
          return age;
      }
      public void setAge(int age) {
          this.age = age;
      }
      @Override
      public String toString() {
          return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
      }
      
    }
    
  • mysql中创建person表如下

    -------------------------------------+
    | person | CREATE TABLE `person` (
      `id` int DEFAULT NULL,
      `name` varchar(20) DEFAULT NULL,
      `age` int DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
    
  • 测试类

    package com.whl.entity;
    
    import java.io.IOException;
    import java.io.Reader;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    public class TestMybatis {
      public static void main(String[] args) throws IOException {
            //
          Reader reader=Resources.getResourceAsReader("conf.xml");
          SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
          //session -- connection
          SqlSession session = sqlSessionFactory.openSession();
            //通过id值来定位写在mapper中的SQL语句
          String statement = "com.whl.entity.PersonMapper.queryPersonById";
            //查询一条,用selectOne,第一个参数是sql,第二个参数是sql中的?
          Person person = session.selectOne(statement,1);
          System.out.println(person);
            //关闭数据库连接
          session.close();
      }
    }
    

Ⅱ、基础方式和mapper动态代理方式

1.基础方式

第一个mybatis程序使用的就是基础方式



  • 输入参数parameterType和输出参数resultType,在形式上都只能有一个
  • 输入参数 :是简单类型(8个基本类型+String)是可以使用任何占位符,#{xxxx};如果是对象类型,则必须是对象的属性#{属性名}
  • 输出参数:如果返回值类型是一个 对象(如Student),则无论返回一个、还是多个,在resultType都写成org.lanqiao.entity.Student,即 resultType="org.lanqiao.entity.Student"
  • 如果使用的事务方式为jdbc,则需要手工commit提交,即session.commit();(增删改需要提交)
  • 所有的标签 select * from person where id = #{id} insert into person(id,name,age) values(#{id},#{name},#{age}) delete from person where id = #{id} update person set name=#{name},age=#{age} where id=#{id}

    PersonMapper接口

    package com.whl.mapper;
    
    import java.util.List;
    import com.whl.entity.Person;
    
    //操作mybatis的接口
    public interface PersonMapper {
        Person queryPersonById(int id);
        List queryAllPerson();
        void addPerson(Person person);
        void deletePersonById(int id);
        void updatePersonById(Person person);
    }
    

    测试类

    package com.whl.entity;
    
    
    import java.io.IOException;
    import java.io.Reader;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.javassist.expr.NewArray;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import com.whl.mapper.PersonMapper;
    
    public class Test {
    
        public static void queryPersonById(int id) throws IOException {
            Reader reader=Resources.getResourceAsReader("conf.xml");
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
            //session -- connection
            SqlSession session = sqlSessionFactory.openSession();
            PersonMapper personMapper=session.getMapper(PersonMapper.class);
            Person person=personMapper.queryPersonById(1);
            System.out.println(person);
            session.close();
        }
        
        public static void queryAllPerson() throws IOException {
            Reader reader=Resources.getResourceAsReader("conf.xml");
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
    
            SqlSession session = sqlSessionFactory.openSession();
            PersonMapper personMapper=session.getMapper(PersonMapper.class);
            List persons=personMapper.queryAllPerson();
            System.out.println(persons);
            session.close();
        }
        
        public static void addPerson(Person person) throws IOException {
            Reader reader=Resources.getResourceAsReader("conf.xml");
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);   
            SqlSession session = sqlSessionFactory.openSession();
            PersonMapper personMapper=session.getMapper(PersonMapper.class);
            personMapper.addPerson(person);
            session.commit();
            System.out.println("增加成功");
            session.close();
        }
        
        public static void deletePersonById(int id) throws IOException {
            Reader reader=Resources.getResourceAsReader("conf.xml");
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);   
            SqlSession session = sqlSessionFactory.openSession();
            PersonMapper personMapper=session.getMapper(PersonMapper.class);
            personMapper.deletePersonById(id);
            session.commit();
            System.out.println("删除成功");
            session.close();
        }
        
        public static void updatePersonById(Person person) throws IOException {
            Reader reader=Resources.getResourceAsReader("conf.xml");
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);   
            SqlSession session = sqlSessionFactory.openSession();
            PersonMapper personMapper=session.getMapper(PersonMapper.class);
            personMapper.updatePersonById(person);
            session.commit();
            System.out.println("修改成功");
            session.close();
        }
        public static void main(String[] args) throws IOException {
            //queryPersonById(1);
            //addPerson(new Person(3,"xxx",19));
            //updatePersonById(new Person(2,"whl",19));
            deletePersonById(3);
            queryAllPerson();       
        }
    }
    

    测试类中最重要的代码

    StudentMapper studentMapper = session.getMapper(StudentMapper.class) ;
    studentMapper.方法();
    

    通过session对象获取接口(session.getMapper(接口.class);),再调用该接口中的方法,程序会自动执行该方法对应的SQL。这样就不需要statement和selectone了

    匹配的过程:

    1. 根据 接口名 找到 mapper.xml文件(根据的是namespace=接口全类名)
    2. 根据 接口的方法名 找到 mapper.xml文件中的SQL标签 (方法名=SQL标签Id值)

    以上2点可以保证: 当我们调用接口中的方法时,程序能自动定位到某一个Mapper.xml文件中的sqL标签

    习惯:SQL映射文件(mapper.xml)和接口放在同一个包中(注意修改conf.xml中加载mapper.xml文件的路径)

    3.优化

    • 可以将配置信息单独放入db.properties文件中,然后再动态引入

      形式:kv对

      driver=com.mysql.cj.jdbc.Driver
      url=jdbc:mysql://localhost:3306/mysqldemo?serverTimezone=UTC
      username=root
      password=123456
      

      db.properties放在源路径

      在conf.xml中用properties标签引入

      
          
          ...
      
      

      通过${key}来取值(类似于EL表达式)

      
      
      
      
      
    • MyBatis全局参数,在conf.xml中设置(一般不进行手动设置,使用默认值)

      在setting标签中进行设置

      
        
        
      
      
    • 别名(单个别名、批量别名),在conf.xml中的typeAliases标签进行设置

      
            
            
            
            
      
      

      除了自定义别名外,MyBatis还内置了一些常见类的别名。

    Ⅲ、类型处理器

    类型处理器:把Java代码中的类型转换成JDBC类型

    1.自带类型处理器

    MyBatis自带一些常见的类型处理器

    image-20200819110702060.png

    2.自定义MyBatis类型处理器

    例:

    实体类Student :  boolean   stuSex;
    true:男
    false:女
    
    表student:   number  stuSex
    1:男
    0:女
    
    1. 创建转换器

      • 直接实现TypeHandler接口

      • 或继承BaseTypeHandler

        package org.lanqiao.converter;
        
        import java.sql.CallableStatement;
        import java.sql.PreparedStatement;
        import java.sql.ResultSet;
        import java.sql.SQLException;
        
        import org.apache.ibatis.type.BaseTypeHandler;
        import org.apache.ibatis.type.JdbcType;
        
        //BaseTypeHandler
        public class BooleanAndIntConverter extends BaseTypeHandler{
        
          //java(boolean)-DB(number)
          /*
           * ps:PreparedStatement对象
           * i:PreparedStatement对象操作参数的位置
           * parameter:java值
           * jdbcType:jdbc操作的数据库类型
           */
          @Override
          public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
                  throws SQLException {
                  if(parameter) {
                      //1
                      ps.setInt(i, 1); 
                  }else {
        //                0
                      ps.setInt(i, 0); 
                  }
          }
        
          //db(number)->java(boolean)
          @Override
          public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {
              int sexNum = rs.getInt(columnName) ;//rs.getInt("stuno") ;
        
              return sexNum == 1?true:false ;
          }
        
          @Override
          public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
              int sexNum = rs.getInt(columnIndex) ;//rs.getInt(1)
              return sexNum == 1?true:false ;
          }
        
          @Override
          public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
              int sexNum = cs.getInt(columnIndex) ;//rs.getInt(1)
              return sexNum == 1?true:false ;
          }
        }
        
    1. 配置conf.xml,通过typeHandler标签配置类型转换器

      
       
      
      
    2. 配置mapper.xml

      
        
      
           
           
           
           
           
           
      
      

      何时使用resultMap?

      • 如果类中属性名和表中的字段名能够合理识别(stuNo -stuno)则可以使用resultType;否则(id-stuno)使用resultMap
      • 如果类中属性和表中的字段类型能够合理识别(String-varchar2),则可以使用resultType;否则(boolean-number)使用resultMap

    Ⅳ、输入参数

    1.简单类型

    • {}、${}的区别

      1. {任意值}

        ${value} ,其中的标识符只能是value

      2. {}自动给String类型加上' '(自动类型转换)

        ${}原样输出,但是适合于动态排序(动态字段)

        select stuno,stuname,stuage  from student where stuname = #{value}
        select stuno,stuname,stuage  from student where stuname = '${value}'
        动态排序:
        select stuno,stuname,stuage  from student  order by ${value} asc
        
      3. {}可以防止SQL注入,${}不防止

    • 相同之处:都可以获取对象的值(嵌套类型对象)

    2.模糊查询获取对象值

    • 方式一:用#{}
      select stuno,stuname,stuage  from student where stuage= #{stuAge}  or stuname like #{stuName} 
    
      Student student = new Student();
      student.setStuAge(24);
      student.setStuName("%w%");//在set时就加入了通配符
      List students = studentMapper.queryStudentBystuageOrstuName(student) ;//接口的方法->SQL
    
    • 方式二:用${}

      student.setStuName("w");
      
      select stuno,stuname,stuage  from student where stuage= #{stuAge}  or stuname like '%${stuName}%'
      

    3.输入对象为HashMap

    在框架学习中HashMap一般是这样声明的(String,Object对)

    Map map = new HashMap<>();
    map.put("stuAge",19);
    
    
    

    Ⅴ、输出参数

    输出参数的四种情况:

    1. 简单类型(8个基本+String)
    2. 输出参数为实体对象类型
    3. 输出参数为实体对象类型的集合 :虽然输出类型为集合,但是resultType依然写 集合的元素类型(resyltType="Student")
    4. 输出参数类型为HashMap
      --HashMap本身是一个集合,可以存放多个元素,
      但是根据提示发现 返回值为HashMap时 ,查询的结果只能是1个学生(no,name);
      -->结论:一个HashMap 对应一个学生的多个元素(多个属性) [一个map,一个学生]

    1.resultMap

    当实体类的属性、数据表的字段:类型、名字不同时,使用resultMap建立起字段名与属性名的映射

    
        
        
        
    
    
    • 用id标签指定主键的映射
    • 用result标签指定非主键的映射
    • property属性的值为属性名,column属性的值为字段名

    2.resultType+HashMap

    通过hashmap把属性名与字段名进行对应

    • 可用AS取别名的方式进行对应,也可以在select语句字段名后空格给出属性名
    
    
    
    
    HashMap person=personMapper.queryPersonByIdWithHashMap(1);
    System.out.println(person);
    //{personName=lxl, personAge=19, personId=1}
    

    注意:以hashmap作为返回类型,其中hashmap存储的是某一个学生的多个属性的键值对,而不是多个学生

    如何返回多个学生?List> persons

    List> persons = personMapper.queryPersonAllWithHashMap();
    System.out.println(persons);
    //[{name=lxl, id=1, age=19}, {name=whl, id=2, age=19}]
    

    Ⅵ、动态SQL

    1.动态生成where子句

    
        
     
         
         
         
     
    
    • where标签:写了后就不用在SQL中手写where关键字了
    • if标签
      • test属性写条件表达式,为true时执行标签内的SQL
      • 注意:条件表达式中写的是对属性名的判断,不同条件用and、or连接
      • 第一个if标签中的SQL是可以加and关键字的,因为mybatis会自动忽略这个and关键字

    我踩的坑:怎么执行查询都是null,后来发现没有配置resultMap。只要是字段和属性名不一样就必须配置!

    2.输入参数为集合或数组

    输入参数是list的情况

        
    
            
            
            
     
    
     
    
    • 所有集合在mapper中都用list来指代,并不使用集合本身的名称
    • foreach标签用于迭代集合
      • collection属性:指定要遍历的集合
      • open和close:只遍历集合中元素,不遍历集合前后的SQL语句。用这两个属性指定前后的SQL
      • item:给集合中每个元素取一个临时的名称。这个名称是无所谓的,只要和标签中#{}的一样就行了
      • separator:分隔符,不加就会变成"id in (123)",需要的是"id in (1,2,3)"
    • 用#{}来取集合中元素的值
    personNos.add(1);
    personNos.add(2);
    //personNos.add(3);
    List persons=personMapper.queryPersonByNolist(personNos);;
    System.out.println(persons);
    //[Person [personId=1, personName=lxl, personAge=19], Person [personId=2, personName=whl, personAge=19]]
    

    输入参数是int数组的情况:

     
    
    • 需要注意集合的大小是size,数组是length
    • 传入的简单类型的数组在mapper中一律以array表示
    int[] personNos=new int[] {1,2,3};
    List persons=personMapper.queryPersonByNoarray(personNos);;
    System.out.println(persons);
    //[Person [personId=1, personName=lxl, personAge=19], Person [personId=2, personName=whl, personAge=19], Person [personId=3, personName=abc, personAge=19]]
    

    输入参数是对象数组的情况:

    
    
    • 注意:所有类的对象数组的parameterType都是Object[]
    • 级联获取对象中的属性值
    Person p1=new Person();
    Person p2=new Person();
    Person p3=new Person();
    p1.setPersonId(1);
    p2.setPersonId(2);
    p3.setPersonId(3);
    Person[] persons1=new Person[] {p1,p2,p3};
    List result=personMapper.queryPersonByObjectarray(persons1);;
    System.out.println(result);
    //[Person [personId=1, personName=lxl, personAge=19], Person [personId=2, personName=whl, personAge=19], Person [personId=3, personName=abc, personAge=19]]
    

    3.提取SQL片段

    
        select * from person
     
    
     
    
    • 用sql标签提取出常用的SQL语句,id标识唯一的SQL语句
    • 用include标签中的refid属性指定要使用的SQL语句的id

    Ⅶ、关联查询

    image-20200822120148468.png
    image-20200822120206489.png

    一对一:association
    一对多:collection

    1.一对一

    方法一:

    1.建一个类,继承自属性多的类,再把多出来的属性写在这个新类里

    package com.whl.entity;
    
    public class PersonBusiness extends Person{
        private int cardId;
        private String cardInfo;
        
        public int getCardId() {
            return cardId;
        }
        public void setCardId(int cardId) {
            this.cardId = cardId;
        }
        public String getCardInfo() {
            return cardInfo;
        }
        public void setCardInfo(String cardInfo) {
            this.cardInfo = cardInfo;
        }
        @Override
        public String toString() {
            return super.toString()+"PersonBusiness [cardId=" + cardId + ", cardInfo=" + cardInfo + "]";
        }   
    }
    
    • 注意tostring方法要重写并调用父类的tostring!

    2.设置person表的cardid为外键

    3.写SQL

    
    
    • 注意返回类型为PersonBusiness(第三个类)

    4.执行

    PersonBusiness personBusiness=personMapper.queryPersonByIdOO(1);
    System.out.println(personBusiness);
    //Person [id=1, name=lxl, age=19]PersonBusiness [cardId=1, cardInfo=lxl info...]
    

    我踩的坑:第一次查询结果只显示了PersonBusiness增加的属性,person中的显示都为null或者0,最后发现是数据库字段名与属性名不一致。修改一致后就可正常显示

    方法二:写一个person类和personcard类,在person类中有一个personcard对象

    public class PersonCard {
        private int cardId;
        private String cardInfo;
    }
    
    public class Person {
        private int id;
        private String name;
        private int age;
        private PersonCard card;//把PersonCard类的对象作为Person类的属性
    }
    
    
        
     
        
        
        
        
            
            
        
     
    
    • resultMap中的type属性为person,因为person包含了PersonCard
    • 一对一关联:用association标签指定一对一
      • property属性的值为Person类中PersonCard对象成员的名称
      • javaType属性指定了card对象的类名
      • id和result标签指定了personcard表与personcard对象字段名、属性名之间的映射关系
    Person person=personMapper.queryPersonByIdOO(1);
    System.out.println(person);
    //Person [id=1, name=lxl, age=19, card=PersonCard [cardId=1, cardInfo=lxl info...]]
    

    2.一对多

    1.写xml

    
        
     
        
           
        
            
            
            
        
     
    
    • collection标签:指定一对多关联查询

    2.写属性类

    public class PersonClass {
        private int classId;
        private String className;
        List persons;
        ...
    }
    
    public class Person {
        private int id;
        private String name;
        private int age;
        private PersonCard card;
        ...
    }
    
    • 班级和学生为一对多关系,所以在PersonClass中用List保存学生
    • card对象作为Person类的成员

    3.测试运行

    PersonClass personClass=personMapper.queryPersonByClassId(1);
    System.out.println(personClass);
    //PersonClass [classId=1, className=c1, persons=[Person [id=1, name=lxl, age=19, card=null]]]
    

    Ⅷ、日志

    可以通过日志信息,相信的阅读mybatis执行情况(观察mybatis实际执行sql语句以及SQL中的参数和返回结果)

    以log4j为例

    1. 引入log4j.jar

    2. 在conf.xml中开启日志

      
       
        
      
      

      如果不指定,Mybatis就会根据以下顺序 寻找日志
      SLF4J →Apache Commons Logging →Log4j 2 → Log4j →JDK logging

    3. 编写配置日志输出文件

      在src下创建log4j.properties

      log4j.rootLogger=DEBUG, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
      

    日志级别:DEBUG

    如果设置为info,则只显示 info及以上级别的信息;
    建议:在开发时设置debug,在运行时设置为info或以上。

    Ⅸ、延迟加载

    也称“懒加载”

    什么是延迟加载:

    在关联查询(一对一、一对多、多对多)中,如果不采用延迟加载(立即加载),查询时会将一和多都查询,班级、班级中的所有学生。如果想要暂时只查询1的一方,而多的一方先不查询而是在需要的时候再去查询-->延迟加载

    1. 开启延迟加载conf.xml配置settings

      
       
       
           
       
       
      
      
    2. 写接口

      List queryPersonByIdOO();
      
    3. 写SQL

      
           
       
           
           
           
           
       
       
      

      新建PersonCardMapper,注意要在conf.xml加载该映射!

      
           
      
      
      • association标签表示一对一,collection表示一对多
        • property表示person类中的card属性
        • javaType写card的类名
        • select属性写PersonCardMapper中的sql的id。形式:namespace.id
        • column关联的外键,作为queryCardById的输入参数
      • queryCardById中的resultType属性:写card类的全名
    4. 测试运行

      List persons=personMapper.queryPersonByIdOO();
      System.out.println(persons);
      for(Person person:persons) {
       //System.out.println(person.getId()+"----"+person.getName());
       PersonCard personCard=person.getCard();
       System.out.println(person);
      }
      //Person [id=1, name=lxl, age=19, card=PersonCard [cardId=1, cardInfo=lxl info...]]
      //Person [id=2, name=whl, age=19, card=PersonCard [cardId=2, cardInfo=whl info...]]
      

    Ⅹ、查询缓存

    一级缓存 :同一个SqlSession对象

    MyBatis默认开启一级缓存,如果用同样的SqlSession对象查询相同的数据,则只会在第一次 查询时 向数据库发送SQL语句,并将查询的结果 放入到SQLSESSION中(作为缓存存在);后续再次查询该同样的对象时,则直接从缓存中查询该对象即可(即省略了数据库的访问)

    二级缓存:MyBatis默认情况没有开启二级缓存,需要手工打开。
    1.conf.xml

    
    
    

    2.在具体的mapper.xml中声明开启(studentMapper.xml中)

    
        
    
    
    • cache标签:声明此namespace开启二级缓存

    根据异常提示:NotSerializableException可知,MyBatis的二级缓存 是将对象 放入硬盘文件中

    准备缓存的对象,必须实现了序列化接口(如果开启的缓存Namespace="org.lanqiao.mapper.StudentMapper"),可知序列化对象为Student,因此需要将Student序列化(序列化Student类,以及Student的级联属性、和父类)

    • 触发将对象写入二级缓存的时机:SqlSession对象的close()方法。

    Mybatis自带二级缓存:[同一个namespace]生成的mapper对象

    回顾:namespace的值就是接口的全类名(包名.类名),通过接口可以产生代理对象(studentMapper对象)

    namespace决定了studentMapper对象的产生

    结论:只要产生的xxxMapper对象 来自于同一个namespace,则 这些对象 共享二级缓存。

    注意:二级缓存 的范围是同一个namespace, 如果有多个xxMapper.xml的namespace值相同,则通过这些xxxMapper.xml产生的xxMapper对象仍然共享二级缓存。

    • 禁用 :select标签中useCache="false"

    清理:

    1.与清理一级缓存的方法相同
    commit(); (一般执行增删改时 会清理掉缓存;设计的原因 是为了防止脏数据)
    在二级缓存中,commit()不能是查询自身的commit。

    commit会清理一级和二级缓存;但是 清理二级缓存时,不能是查询自身的commit;
    2. 在select标签中 增加属性 flushCache="true"

    命中率:缓存中存在就是命中。命中数/查询数

    三方提供的二级缓存:ehcache、memcache

    要想整合三方提供的二级缓存 (或者自定义二级缓存),必须实现org.apache.ibatis.cache.Cache接口,该接口的默认实现类是PerpetualCache

    整合ehcache二级缓存:

    1. ehcache-core.jar mybatis-Ehcache.jar slf4j-api.jar
    2. 编写ehcache配置文件 Ehcache.xml
    3. 开启EhCache二级缓存
      在xxxMapper.xml中开启
    
        
        
        
    
    

你可能感兴趣的:(Mybatis入门)