栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis学习笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis学习笔记

Mybatis 第一章 概述 1.1 什么是mybatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2 为什么需要mybaits?

主要就是简化了jdbc操作,能够更方便的操作数据库。

1.3 Mybatis的特点

简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
提供xml标签,支持编写动态sql。

第二章 环境搭建

这里以查询员工表信息为例子

a>引入依赖


    org.mybatis
    mybatis
    3.4.1



    mysql
    mysql-connector-java
    8.0.21


    junit
    junit
    4.12
    test

b>创建实体类

public class Employee {
   
   private Integer id;
   private String lastName;
   private String email;
   private String gender;

   public Integer getId() {
      return id;
   }

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

   public String getLastName() {
      return lastName;
   }

   public void setLastName(String lastName) {
      this.lastName = lastName;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public String getGender() {
      return gender;
   }

   public void setGender(String gender) {
      this.gender = gender;
   }

   @Override
   public String toString() {
      return "Employee{" +
            "id=" + id +
            ", lastName='" + lastName + ''' +
            ", email='" + email + ''' +
            ", gender='" + gender + ''' +
            '}';
   }
}

c>创建全局配置文件mybatis-config




    
        
            
            
                
                
                
                
            
        
    
    
    
        
    

d>编写sql映射文件EmployeeMapper.xml







    
      select id,last_name lastName,email,gender from employee where id = #{id}
   


e>测试

import com.qy.mybatis.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class test {


    

    public SqlSessionFactory getSqlSessionFactory() throws IOException, IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }


    @Test
    public void test1() throws IOException {

        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        try {
            Employee employee = openSession.selectOne(
                    "abc.getEmpById", 1);
            System.out.println(employee);
        } finally {
            openSession.close();
        }

    }





}

以上方法,我们在调用的使用,需要加上命名空间+sql唯一标注很不方便。我们可以才有接口式编程

a>创建一个Dao接口

public interface EmployeeDao  {

    Employee getEmpById(Integer id);
}

b>sql映射文件的命名空间指向这个接口并且sql的id和方法名保持一致







    
	select * from employee where id = #{id}


		select id,last_name ,email,gender from employee where id = #{id}
	

	
	    insert into employee(last_name,email,gender)
		values(#{lastName},#{email},#{gender})
	

	
		update employee
		set
		last_name = #{lastName}
		where
		id = #{id}
	

	
		delete  from employee
		where
		id = #{id}
	




3.测试

  @Test
    public void test3() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
        Employee addEmployee =  new Employee();
        addEmployee.setLastName("小王");
        addEmployee.setGender("0");
        addEmployee.setEmail("xiaowang@qq.com");
        Integer integer = employeeDao.addEmp(addEmployee);
        System.out.println(integer);

        Employee updateEmployee = new Employee();
        updateEmployee.setId(2);
        updateEmployee.setLastName("qianyue");
        updateEmployee.setEmail("qianyue@qq.com");
        updateEmployee.setGender("0");
        employeeDao.updateEmp(updateEmployee);


        employeeDao.deleteEmp(1);

        openSession.commit();




    }

注意:

mybatis允许增删改直接定义以下类型返回值
Integer、Long、Boolean、void
我们需要手动提交数据
sqlSessionFactory.openSession();=》手动提交
sqlSessionFactory.openSession(true);
=》自动提交

4.2 获取自增主键的值

获取自增主键的值:

1.mysql

mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys=“true”;使用自增主键获取主键值策略
keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
代码演示

	
	    insert into employee(last_name,email,gender)
		values(#{lastName},#{email},#{gender})
	

这样我们可以通过插入的这个类对象获取主键值

2.Oracle

  • Oracle不支持自增;Oracle使用序列来模拟自增;
  • 每次插入的数据的主键是从序列中拿到的值;如何获取到这个值;
#从序列获取新主键值
select employee_seq.nextval from dual;

oracle 通过selectKey 获取序列值


	
	
		
		
		select EMPLOYEES_SEQ.nextval from dual 
		
	
	
	
	
	insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
	values(#{id},#{lastName},#{email}) 

	

第五章 参数处理 5.1 封装参数
  • 单个参数:mybatis不会做特殊处理 #{参数名/任意值}取值

  • 多个参数:mybatis会做特殊处理

    • 通常操作

      • 方法public Employee getEmpByIdAndLastName(Integer id,String lastName);
      • 取值 #{id},#{lastName}
    • 上述操作会抛出异常Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found.

    • 多个参数会被mybatis拼接为一个map

      • key:param1…paramN或者参数的索引 0 ,1
      • value:传入的参数值
    • #{} 获取指定key的值

  • 命名参数:明确指定封装参数时map的key;@Param(“id”)

    Employee getEmpByIdAndLastName(@Param("id") Integer id, @Param("lastName") String lastName);
    
    • 多个参数会被封装成 一个map
      • key:使用@Param注解指定的值
      • value:参数值
    • #{指定的key}
  • POJO/MAP/TO

    • POJO 如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo

    • Map 如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map

    • TO 如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象,如:’

      Page{
      	int index;
      	int size;
      }
      
  • 扩展思考

    public Employee getEmp(@Param(“id”)Integer id,String lastName);

    • 取值:id==>#{id/param1} lastName==>#{param2}

    public Employee getEmp(Integer id,@Param(“e”)Employee emp);

    • 取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}

    如果参数是Collection(List、Set)类型或者是数组,

    • 也会特殊处理。也是把传入的list或者数组封装在map中
    • key:Collection(collection),如果是List还可以使用这个key(list)
    • public Employee getEmpById(List ids);
      • 取值:取出第一个id的值: #{list[0]}
  • 源码分析

    EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);获取的是代理对象

    • (@Param(“id”)Integer id,@Param(“lastName”)String lastName);

    • ParamNameResolver类中的getNamedParams解析参数封装map的;

    • names:{0=id, 1=lastName};构造器的时候就确定好了

      1.获取每个标了param注解的参数的@Param的值:id,lastName; 赋值给name;

      2.每次解析一个参数给map中保存信息:(key:参数索引,value:name的值)

      name的值:
      标注了param注解:注解的值

      没有标注:
      1.全局配置:useActualParamName(jdk1.8):name=参数名
      2.name=map.size();相当于当前元素的索引
      {0=id, 1=lastName,2=2}

      public Object getNamedParams(Object[] args) {
        final int paramCount = names.size();
        if (args == null || paramCount == 0) {
          return null;
        } else if (!hasParamAnnotation && paramCount == 1) {
          return args[names.firstKey()];
        } else {
          final Map param = new ParamMap();
          int i = 0;
          for (Map.Entry entry : names.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey()]);
            // add generic param names (param1, param2, ...)
            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;
        }
      }
         
      5.2 参数取值 
      

      #{}和${}都可以获取map或实体类中的值

      区别:

      • #{} : 是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
      • ${} : 取出的值直接拼装在sql语句中;会有安全问题;

      大多情况下,我们去参数的值都应该去使用#{}。

      原生jdbc不支持占位符的地方我们就可以使用${}进行取值,比如分表、排序。。。;按照年份分表拆分

      select * from ${year}_salary where xxx;
      select * from tbl_employee order by ${f_name} ${order}
      

      什么是sql注入

      5.3 取值时指定参数规则

      #{}:更丰富的用法:

      规定参数的一些规则:

      • javaType、
      • jdbcType、
      • mode(存储过程)、
      • numericScale、
      • resultMap、
      • typeHandler、
      • jdbcTypeName、
      • expression(未来准备支持的功能);

      jdbcType通常需要在某种特定的条件下被设置:

      在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle DB(报错);
      JdbcType OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,Oracle DB不能正确处理;由于全局配置中:jdbcTypeForNull=OTHER,Oracle DB不支持,两种解决方法:

      1. 在mapper文件中写#{email,jdbcType=NULL};
      2. 在全局配置文件
      第六章 返回类型处理 6.1 返回list集合
      
      
         select * from employee
      
      
      6.2 返回map
      //返回多条通过@MapKey指定返回的map中key对应的字段
      @MapKey("lastName")
      Map getEmpReturnMap();
      //返回一条记录的map;key就是列名,值就是对应的值
      public Map getEmpByIdReturnMap(Integer id);
      
      
      	
      	
         select id,last_name ,email,gender from employee where id = #{id}
      
      
      6.4 关联查询结果处理 6.4.1 环境搭建

      部门和员工实体类搭建

      public class Department {
      
         private Integer id;
         private String departmentName;
         private List empList;
      }
      
      public class Employee {
         
         private Integer id;
         private String lastName;
         private String email;
         private String gender;
         private Department department;
         }
      

      数据库中 员工表的外键department_id是部门表的主键

      6.4.2 级联属性封装结果

      a>类中嵌套类

      员工和部门之间的关系

      查询员工信息的时候把部门名称也查询出来

      (1)普通级联映射

      
      		
      		
      		
      		
      		
      		
      		
      	
      
      	
         select
          e.id id,
          e.last_name lastName,
          e.gender gender,
          e.email email,
          e.department_id department_id,
          d.id d_id,
          d.department_name department_name
          from  employee e ,department d
          where
          e.department_id = d.id
          and e.id=#{id}
      
      

      (3)association分步查询

      DepartmentDao.java

      public interface DepartmentDao {
          Department getDeptById(Integer id);
      
      }
      

      DepartmentMapper.xml

      
      
      
      
          
      		select
      		 e.id id,
      		 e.last_name lastName,
      		 e.gender gender,
      		 e.email email,
      		 e.department_id department_id
      		 from  employee e
      		 where
      		 e.id=#{id}
      	
      

      (4)分步查询&延迟加载

      我们每次查询Employee对象的时候,都将一起查询出来。部门信息在我们使用的时候再去查询;分段查询的基础之上加上两个配置:

      在全局配置文件中配置,实现懒加载

      mybatis-config.xml

          
              
              
          
               
      

      (5)collection封装结果

      比如 我们要查询一个部门下的所有员工

      DepartmenDao

      Department getDeptByIdPlus(Integer id);
      

      DepartmenMapper.xml

      
      		
      		
      		
      		
      			
      			
      			
      			
      		
      	
      
      	
      		select id,department_name  departmentName from department where id = #{id}
      	
      

      (6)分步查询传递多列值&fetchType

      • 多列的值传递过去:
        • 将多列的值封装map传递;column="{key1=column1,key2=column2}"
        • key的第二步查询中#{}的参数名
      • fetchType=“lazy”:表示使用延迟加载;
        • lazy:延迟 默认
        • eager:立即
      
      
         
         
      
         
      
         
      
      
      
      
      
         select *
         from employee
         where 1=1
         
         
            and id=#{id}
         
         
            and last_name like #{lastName}
         
         
            and email=#{email}
         
         
         
            and gender=#{gender}
         
      
      
      
      7.2 动态sql-where-查询条件

      查询的时候如果某些条件没带可能sql拼装会有问题

      1.给where后面加上1=1,以后的条件都and xxx。
      2.mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉(where只会去掉第一个多出来的and或者or,但最后一个多出来的and或者or则不会去掉。

      DynamicSQLMapper

      public List getEmpListByConditionWhere(Employee employee);
      

      DynamicSQLMapper.xml

      
      			select *
      			from employee
      			
      			
      				
      					and id=#{id}
      				
      				
      					and last_name like #{lastName}
      				
      				
      					and email=#{email}
      				
      				
      				
      					and gender=#{gender}
      				
      			
      
      
      
      	
      
      7.4 动态sql-choose-分支选择

      choose相当于 case when break 分支选择 选择其中的一个

      DynamicSQLMapper

      public List getEmpListByConditionChoose(Employee employee);
      

      DynamicSQLMapper.xml

      
      		select *
      		from employee
      
      		
      			id in
      
      			
      				#{item}
      			
      		
      	
      
      7.7 动态sql-foreach-mysql下foreach批量插入的两种方式

      mysql支持 insert 表名(字段) values (),(),()方式 和 insert 表名 values();insert 表名 values();insert 表名 values(); 两种方式

      方式一:

      DynamicSQLMapper

      	public void  insertForeach1(@Param("employeeList") List employeeList);
      

      DynamicSQLMapper.xml

      	
      		insert  employee(last_name,email,gender,department_id)
      		values
      		
      			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
      		
      
      
      	
      

      方式二

      注意这种方式需要配置数据库连接url属性allowMultiQueries=true

      jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&allowMultiQueries=true"
      

      DynamicSQLMapper

      	public void  insertForeach2(@Param("employeeList") List employeeList);
      

      DynamicSQLMapper.xml

      
      
         
            insert into employee(last_name,email,gender,department_id)
            values(
            #{emp.lastName},
            #{emp.email},
            #{emp.gender},
            #{emp.department.id})
         
      
      
      
      7.8动态sql-foreach-oracle下批量插入的两种方式

      Oracle数据库批量保存:

      • Oracle不支持values(),(),()

      Oracle支持的批量方式:

      1. 多个insert放在begin - end里面
      2. 利用中间表
      # 多个insert放在begin - end里面
      begin
          insert into employees(employee_id,last_name,email) 
          values(employees_seq.nextval,'test_001','test_001@atguigu.com');
          insert into employees(employee_id,last_name,email) 
          values(employees_seq.nextval,'test_002','test_002@atguigu.com');
      end;
      
      # 利用中间表
      insert into employees(employee_id,last_name,email)
         select employees_seq.nextval,lastName,email from(
                select 'test_a_01' lastName,'test_a_e01' email from dual
                union
                select 'test_a_02' lastName,'test_a_e02' email from dual
                union
                select 'test_a_03' lastName,'test_a_e03' email from dual
         );
      
      

      方式一

      
      	
      	
      		insert into employees(employee_id,last_name,email) 
      	    values(employees_seq.nextval,#{emp.lastName},#{emp.email});
      	 
      
      	
      
      
      

      方式二

      
      	
      	insert into employees(employee_id,last_name,email)
      	
      		select #{emp.lastName} lastName,#{emp.email} email from dual
      	
      
      
      7.9 动态sql-内置参数 _parameter & _databaseId

      不只是方法传递过来的参数可以被用来判断,

      mybatis默认还有两个内置参数:

      _parameter:代表整个参数
      单个参数:_parameter就是这个参数
      多个参数:参数会被封装为一个map;_parameter就是代表这个map
      _databaseId:如果配置了databaseIdProvider标签。
      _databaseId就是代表当前数据库的别名oracle

      
      
      
      	
      		select * from tbl_employee
      		
      			where last_name like #{_parameter.lastName}
      		
      	
      
      	
      		select * from employees
      		
      			where last_name like #{_parameter.lastName}
      		
      	
      
      
      7.10 动态sql-bind-绑定
      
      
      		select
      		
      		from employee
      	
      
      第八章 缓存

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

      MyBatis系统中默认定义了两级缓存,一级缓存和二级缓存。

      默认情况下,只有一级缓存( SqlSession级别的缓存,也称为本地缓存)开启。
      二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
      为了提高扩展性。 MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

      8.1 一级缓存

      一级缓存(local cache),即本地缓存,作用域默认为sqlSession。当 Session flush 或 close 后, 该Session 中的所有 Cache 将被清空。
      本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域.
      在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置

      同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中

      key = hashCode + 查询的SqlId + 编写的sql查询语句 + 参数
      一级缓存失效的四种情况:

      不同的SqlSession对应不同的一级缓存
      同一个SqlSession但是查询条件不同
      同一个SqlSession两次查询期间执行了任何一次增删改操作
      同一个SqlSession两次查询期间手动清空了缓存

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

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

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

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

      • 使用步骤

        1. 全局配置文件中开启二级缓存
        2. 需要使用二级缓存的映射文件处使用cache配置缓存
        3. 注意: POJO需要实现Serializable接口

      cache标签的属性:

      eviction:缓存的回收策略:
      LRU – 最近最少使用的:移除最长时间不被使用的对象。
      FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
      SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
      WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
      默认的是 LRU。
      flushInterval:缓存刷新间隔
      缓存多长时间清空一次,默认不清空,设置一个毫秒值
      readOnly:是否只读:
      true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
      false:非只读:mybatis觉得获取的数据可能会被修改。mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢
      size:缓存存放多少元素;
      type=“”:指定自定义缓存的全类名;
      实现Cache接口即可;
      tip:mybatis必须是会话关闭或者提交后 一级缓存的数据才会转移到二级缓存中

      代码演示

      1.全局配置文件中配置二级缓存

              
              
      

      2.mapper文件中添加cache标签

      
      

      3.实体类实现序列号接口

      public class Employee  implements Serializable 
      

      4.测试

       @Test
          public void test22() throws IOException {
      
              SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
              SqlSession openSession1 = sqlSessionFactory.openSession();
              SqlSession openSession2 = sqlSessionFactory.openSession();
              try {
                  EmployeeDao mapper1 = openSession1.getMapper(EmployeeDao.class);
                  EmployeeDao mapper2 = openSession2.getMapper(EmployeeDao.class);
                  Employee empById1 = mapper1.getEmpById(2);
                  System.out.println(empById1);
                  
                  openSession1.close();
                  Employee empById2 = mapper2.getEmpById(2);
                  System.out.println(empById2);
      
                  openSession2.close();
              }finally {
      
              }
      
          }
      
      8.3 和缓存相关的设置

      全局setting的cacheEnable:
      – 配置二级缓存的开关。一级缓存一直是打开的。
      select标签的useCache属性:
      – 配置这个select是否使用二级缓存。一级缓存一直是使用的
      每个增删改查标签的flushCache属性:
      – 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。

      – 询默认flushCache=false。
      sqlSession.clearCache():
      – 只是用来清除一级缓存。
      全局setting的localCacheScope:

      -本地缓存作用域:SESSION:当前会话的所有数据保存在会话缓存中;STATEMENT:可以禁用一级缓存。

      8.4 缓存示意图

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWcsJJ4P-1650933511434)(C:UserswcyAppDataRoamingTyporatypora-user-imagesimage-20220224130400636.png)]

      8.5 第三方缓存整合原理
      • EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
      • MyBatis定义了Cache接口方便我们进行自定义扩展
      //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by Fernflower decompiler)
      //
      
      package org.apache.ibatis.cache;
      
      import java.util.concurrent.locks.ReadWriteLock;
      
      public interface Cache {
          String getId();
      
          void putObject(Object var1, Object var2);
      
          Object getObject(Object var1);
      
          Object removeObject(Object var1);
      
          void clear();
      
          int getSize();
      
          ReadWriteLock getReadWriteLock();
      }
      

      整合步骤

      1.导入依赖

      
          org.mybatis.caches
          mybatis-ehcache
          1.2.1
      
      

      2.编写ehcache.xml文件

      
      
          
          
      
          
          
      
      
              
      
      

      3.mapper映射文件中添加cache标签 并指明type

      
      

      另外:

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

      
      
      第九章 SSM整合

      1.配置web.xml

      
      
      
        Archetype Created Web Application
      
      
        
        
          contextConfigLocation
          classpath:applicationContext.xml
        
        
        
          org.springframework.web.context.ContextLoaderListener
        
        
        
        
          dispatcherServlet
          org.springframework.web.servlet.DispatcherServlet
          
      
            
            contextConfigLocation
            
            classpath:springMVC.xml
          
      
          
          1
        
      
        
          dispatcherServlet
          /
        
      
      
      
      

      2.配置SpringMVC.xml

      
      
      
      
      
          
          
          
              
          
      
      
          
          
              
              
          
          
          
          
          
      
          
      
      
      
      

      3.配置applicationContext.xml

      
      
      
          
          
              
          
      
      
          
          
              
              
              
              
          
      
          
          
              
          
      
          
          
      
          
              
          
      
          
          
          
              
              
              
              
              public Object pluginAll(Object target) {
          for (Interceptor interceptor : interceptors) {
            target = interceptor.plugin(target);
          }
          return target;
        }
      
      

      默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

      Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
      ParameterHandler (getParameterObject, setParameters)
      ResultSetHandler (handleResultSets, handleOutputParameters)
      StatementHandler (prepare, parameterize, batch, update, query)
      插件开发的步骤

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

        package com.qy.mybatis.Interceptors;
        
        import org.apache.ibatis.executor.statement.StatementHandler;
        import org.apache.ibatis.plugin.*;
        
        import java.util.Properties;
        
        
        
        
        @Intercepts({
                @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
        })
        public class FirstPlugin  implements Interceptor {
        
            
            public Object intercept(Invocation invocation) throws Throwable {
                System.out.println("FirstPlugin-->intercept");
                
                System.out.println("拦截到的对象是"+invocation.getTarget());
                Object proceed = invocation.proceed();
                return proceed;
            }
            
            public Object plugin(Object target) {
                
                System.out.println("被包装的对象是"+target);
                Object wrap = Plugin.wrap(target, this);
                return wrap;
            }
            
            public void setProperties(Properties properties) {
                System.out.println(properties);
        
            }
        }
        
        
      2. 在全局配置文件中注册插件

            
                
                    
                
            
        
        

        插件原理

        按照插件注解声明,按照插件配置顺序调用插件plugin方法,生成被拦截对象的动态代理
        多个插件依次生成目标对象的代理对象,层层包裹,先声明的先包裹;形成代理链
        目标方法执行时依次从外到内执行插件的intercept方法。
        多个插件情况下,我们往往需要在某个插件中分离出目标对象。可以借助MyBatis提供的SystemMetaObject类来进行获取最后一层的h以及target属性的值

      转载请注明:文章转载自 www.mshxw.com
      我们一直用心在做
      关于我们 文章归档 网站地图 联系我们

      版权所有 (c)2021-2022 MSHXW.COM

      ICP备案号:晋ICP备2021003244-6号