java中增删改查的基础代码

java中增删改查的基础代码Mybatis 相关概念 对象 关系数据库映射 ORM ORM 全称 Object Relation Mapping 表示对象 关系映射的缩写 ORM 完成面向对象的编程语言到关系数据库的映射 当 ORM 框架完成映射后 程序员既可以利用面向对象程序设计语言的简单易用性 又可以利用关系数据库的技术优势 ORM 把关系数据库包装成面向对象的模型

大家好,我是讯享网,很高兴认识大家。



Mybatis相关概念

对象/关系数据库映射(ORM)

ORM全称Object/Relation Mapping:表示对象-关系映射的缩写,ORM完成面向对象的编程语言到关系数据库的映射。当ORM框架完成映射后,程序员既可以利用面向对象程序设计语言的简单易用性,又可以利用关系数据库的技术优势。ORM把关系数据库包装成面向对象的模型。ORM框架是面向对象设计语言与关系数据库发展不同步时的中间解决方案。采用ORM框架后,应用程序不再直接访问底层数据库,而是以面向对象的放松来操作持久化对象,而ORM框架则将这些面向对象的操作转换成底层SQL操作。ORM框架实现的效果:把对持久化对象的保存、修改、删除 等操作,转换为对数据库的操作

Mybatis简介

MyBatis是一款优秀的基于ORM的半自动轻量级持久层框架【半自动指的是MyBatis还需要自己编写SQL语句】,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的POJO (Plain Old Java Objects,普通老式Java对 象)为数据库中的记录。

Mybatis历史

原是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了 google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

Mybatis优势

Mybatis是一个半自动化的持久层框架,对开发人员开说,核心sql还是需要自己进行优化,sql和java编码进行分离,功能边界清晰,一个专注业务,一个专注数据。

分析图示如下:

image.png

Mybatis基本应用

快速入门

MyBatis官网地址:www.mybatis.org/mybatis-3/

开发步骤:

  • ①添加MyBatis的坐标
  • ②创建user数据表
  • ③编写User实体类
  • ④编写映射文件UserMapper.xml
  • ⑤编写核心文件SqlMapConfig.xml
  • ⑥编写测试类

环境搭建

1)导入MyBatis的坐标和其他相关坐标

 
讯享网 

2) 创建user数据表

image.png

3) 编写User实体

讯享网

4)编写UserMapper映射文件

 

5) 编写MyBatis核心文件

讯享网

jdbc.properties文件如下:

 

6) 编写测试代码

 

MyBatis的CRUD操作

MyBatis的插入数据操作

1)编写UserMapper映射文件

 

2)编写插入实体User的代码

 

3)插入操作注意问题

  • 插入语句使用insert标签
  • 在映射文件中使用parameterType属性指定要插入的数据类型
  • Sql语句中使用#{实体属性名}方式引用实体中的属性值
  • 插入操作使用的API是sqlSession.insert(“命名空间.id”,实体对象);
  • 插入操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()
MyBatis的修改数据操作

1)编写UserMapper映射文件

 

2)编写修改实体User的代码

 

3)修改操作注意问题

  • 修改语句使用update标签
  • 修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);
MyBatis的删除数据操作

1)编写UserMapper映射文件

 

2)编写删除数据的代码

 

3)删除操作注意问题

  • 删除语句使用delete标签
  • Sql语句中使用#{任意字符串}方式引用传递的单个参数
  • 删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

MyBatis的映射文件概述

image.png

入门核心配置文件分析

image.png

MyBatis常用配置解析

1)environments标签

数据库环境的配置,支持多环境配置

image.png

其中,事务管理器(transactionManager)类型有两种:

  • JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  • MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。

其中,数据源(dataSource)类型有三种:

  • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
  • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
  • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

2)mapper标签

该标签的作用是加载映射的,加载方式有如下几种

  • 使用相对于类路径的资源引用,例如:
 
  • 使用完全限定资源定位符(URL),例如:
 
  • 使用映射器接口实现类的完全限定类名,例如:
 
  • 将包内的映射器接口实现全部注册为映射器,例如:
 

Mybatis相应API介绍

SqlSession工厂构建器SqlSessionFactoryBuilder

常用API:SqlSessionFactory build(InputStream inputStream)

通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

 

其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。

SqlSession工厂对象SqlSessionFactory

SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:

image.png

SqlSession会话对象

SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。

执行语句的方法主要有:

 

操作事务的方法主要有:

 

Mybatis的Dao层实现

传统开发方式

编写UserDao接口

 

编写UserDaoImpl实现

 

测试传统方式

 

代理开发方式

代理开发方式介绍

采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper 接口开发需要遵循以下规范:

  • Mapper.xml文件中的namespace与mapper接口的全限定名相同
  • Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
  • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

编写UserMapper接口

image.png

测试代理方式

 

Mybatis配置文件深入

核心配置文件SqlMapConfig.xml

MyBatis核心配置文件层级关系

image.png

MyBatis常用配置解析

1)environments标签

参考上面

2)mapper标签

参考上面

3)Properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

image.png

4)typeAliases标签

类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下

image.png

配置typeAliases,为com.lagou.domain.User定义别名为user

image.png

但是如果一个项目有几百个实体类,这样就得配置一百多个标签,很麻烦,可以修改为包配置,即指定包下面的实体类使用类名作为别名不区分大小写

 

上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名

image.png

映射配置文件mapper.xml

动态sql语句概述

Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动

态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。

参考的官方文档,描述如下:

image.png

动态SQL之if跟where

我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查

询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰

到。

编写Dao层接口如下:

 

只用if判断时,需要额外加上where 1 = 1 恒等条件,动态SQL编写如下:

 

where标签的作用:会提供where关键字并且去掉第一个and关键字

所以上述的动态SQL可以改写如下:

 

当查询条件id和username都存在时,控制台打印的sql语句如下:

image.png

当查询条件只有id存在时,控制台打印的sql语句如下:

image.png

动态SQL之foreach

循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。

编写Dao层接口如下:

 

xml如下:

 

foreach标签的属性含义如下:

  • collection:代表要遍历的集合元素,注意编写时不要写#{}
  • open:代表语句的开始部分
  • close:代表结束部分
  • item:代表遍历集合的每个元素,生成的变量名
  • sperator:代表分隔符

测试代码片段如下:

image.png

SQL片段抽取之include

Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。

 

Mybatis复杂映射开发

一对一查询

一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

image.png

一对一查询的语句

对应的sql语句:select * from orders o,user u where o.uid=u.id;

查询的结果如下:

image.png

创建Order和User实体

 
 

创建OrderMapper接口

 

配置OrderMapper.xml

 

本质就是将SQL查询出来的列名与实体类的属性进行映射。

image.png

测试结果

image.png

image.png

一对多查询

一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单。

image.png

一对多查询的语句

对应的sql语句:select *,o.id oid from user u left join orders o on u.id=o.uid;

查询的结果如下:

image.png

修改User实体

 

创建UserMapper接口

 

配置UserMapper.xml

 

测试结果

image.png

多对多查询

多对多查询的模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

image.png

多对多查询的语句

对应的sql语句:select u.,r.,r.id rid from user u left join user_role ur on u.id=ur.user_id inner join role r on ur.role_id=r.id;

查询的结果如下

image.png

创建Role实体,修改User实体

 

添加UserMapper接口方法

 

配置UserMapper.xml

 

测试结果

image.png

Mybatis注解开发

MyBatis的常用注解

这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper

映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

  • @Insert:实现新增
  • @Update:实现更新
  • @Delete:实现删除

  • @Select:实现查询
  • @Result:实现结果集封装
  • @Results:可以与@Result 一起使用,封装多个结果集
  • @One:实现一对一结果集封装
  • @Many:实现一对多结果集封装

MyBatis的增删改查

dao接口中的代码如下:

 

注意,在SqlMapConfig.xml指定的应该是mapper接口的路径,而不再是mapper.xml的路径,所以必须使用如下配置:

 

使用class指定的话,每一个mapper都得写一个很麻烦,直接使用package扫描包很方便。注意此时mapper.xml应该不能与mapper的路径一样,否则会出现重复的错误。

MyBatis的注解实现复杂映射开发

实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用

@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置。

image.png

image.png

一对一查询

一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户.

image.png

一对一查询的语句

对应的sql语句:

 

查询的结果如下:

image.png

创建Order和User实体

 

创建OrderMapper接口

 
 

查询分析图如下

image.png

测试结果

 

image.png

一对多查询

一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

image.png

一对多查询的语句

对应的sql语句:

 

查询的结果如下:

image.png

修改User实体

 

创建UserMapper接口

 
 

测试结果

image.png

多对多查询

多对多查询的模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色。

java中增删改查的基础代码image.png

多对多查询的语句

对应的sql语句:

 

image.png

创建Role实体,修改User实体

 

添加UserMapper接口方法

 
 

测试结果

image.png

Mybatis缓存

一级缓存

①、在一个sqlSession中,对User表根据id进行两次查询,查看他们发出sql语句的情况

 

查看控制台打印情况:

image.png

② 、同样是对user表进行两次查询,只不过两次查询之间进行了一次update操作。

 

查看控制台打印情况:

image.png

③、总结

  • 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从 数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
  • 如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的 一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  • 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
  • 手动调用sqlSession.clearCache()同样也会清空一级缓存。

image.png

暂时理解SqlSession缓存中的HashMao结构中的Key由如下组成:由statmentId(即namespace.id),param(即sql的占位符参数值),BoundSql,rowBounds(分页对象)

value是查询的结果

一级缓存原理探究与源码分析

一级缓存到底是什么?一级缓存什么时候被创建、一级缓存的工作流程是怎样的?相信你现在应该会有这几个疑问,那么我们本节就来研究一下一级缓存的本质

大家可以这样想,上面我们一直提到一级缓存,那么提到一级缓存就绕不开SqlSession,所以索性我们 就直接从SqlSession,看看有没有创建缓存或者与缓存有关的属性或者方法。

image.png

调研了一圈,发现上述所有方法中,好像只有clearCache()和缓存沾点关系,那么就直接从这个方法入手吧,分析源码时,我们要看它(此类)是谁,它的父类和子类分别又是谁,对如上关系了解了,你才会对这个类有更深的认识,分析了一圈,你可能会得到如下这个流程图。

image.png

image.png

image.png

image.png

image.png

image.png

再深入分析,流程走到Perpetualcache中的clear()方法之后,会调用其cache.clear()方法,那么这个cache是什么东西呢?点进去发现,cache其实就是private Map cache = new HashMap();也就是一个Map,所以说cache.clear()其实就是map.clear(),也就是说,缓存其实就是本地存放的一个map对象,每一个SqISession都会存放一个map对象的引用,那么这个cache是何时创建的呢

你觉得最有可能创建缓存的地方是哪里呢?我觉得是Executor,为什么这么认为?因为Executor是执行器,用来执行SQL请求,而且清除缓存的方法也在Executor中执行,所以很可能缓存的创建也很 有可能在Executor中,看了一圈发现Executor中有一个createCacheKey方法,这个方法很像是创建缓存的方法啊,跟进去看看,你发现createCacheKey方法是由BaseExecutor执行的,代码如下:

 

接着看一下CacheKey中的update方法如下:

image.png

image.png

创建缓存key会经过一系列的update方法,udate方法由一个CacheKey这个对象来执行的,这个update方法最终由updateList的list来把五个值存进去,对照上面的代码和下面的图示,你应该能 理解这五个值都是什么了

image.png 这里需要注意一下最后一个值,configuration.getEnvironment().getId()这是什么,这其实就是 定义在SqlMapConfig.xml中的标签,见如下。

 

那么我们回归正题,那么创建完缓存之后该用在何处呢?总不会凭空创建一个缓存不使用吧?绝对不会的,经过我们对一级缓存的探究之后,我们发现一级缓存更多是用于查询操作,毕竟一级缓存也叫做查询缓存吧,为什么叫查询缓存我们一会儿说。我们先来看一下这个缓存到底用在哪了,我们跟踪到BaseExecutor中的query方法如下:

image.png

image.png

如果查不到的话,就从数据库查,在queryFromDatabase中,会对localcache进行写入。 localcache对象的put方法最终交给Map进行存放

image.png

二级缓存

二级缓存的原理和一级缓存原理一样,第一次查询,会将数据放入缓存中,然后第二次查询则会直接去缓存中取。但是一级缓存是基于sqlSession的,而二级缓存是基于mapper文件的namespace的,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace 相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中。

image.png

注意:MyBatis的一级缓存是默认开启的,但是二级缓存不是,需要手动配置

①、基于注解的方式简单演示如下:

1.首先在SqlMapConfig.xml配置文件中开启二级缓存(其实默认该配置也是true)

 

2.接着在IUserMapper接口中加入注解@CacheNamespace,代码如下:

 

3.将实体类必须实现序列化接口Serializable,如下;

 

这是为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo都去实现Serializable接口。

4.编写测试类如下:

 

演示发现第第二次查询时,没有打印SQL,并且日志显示缓存命中,说明第一次查询把数据库中数据存入到二级缓存中,第二查询直接从缓存中取数据。但是上述代码中打印的user对象的地址不一样,这是为什么?

因为二级缓存中缓存的是对象的数据,而不是对象本身,即从二级缓存中取数据时,会将之前缓存的数据另外封装成一个新的对象返回。

如果在两个查询中间进行增删改,移交事务操作的话同样也会清空二级缓存,,代码演示如下:

 

上述代码中两次查询都会查询数据库,因为中间增加了更新操作,会清空二级缓存

image.png

useCache和flushCache

当然也可以指定每一个查询方法不使用二级缓存(即该查询禁用二级缓存),可以通过@Options(useCache = false)来设置。代码如下:

 

在mapper的同一个namespace中,如果有其它insert、update, delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。设置statement配置中的flushCache="true”属性,默认情况下为true,即刷新缓存,如果改成false则 不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。所以我们不用设置,默认即可。

②、基于xml的方式简单演示如下:

1.首先在SqlMapConfig.xml配置文件中开启二级缓存(其实默认该配置也是true),这里跟注解方式一样。

 

2.其次在UserMapper.xml文件中开启缓存

 

我们可以看到mapper.xml文件中就这么一个空标签,其实这里可以配置,PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现Cache接口来自定义缓存。

image.png

 

我们可以看到二级缓存底层还是HashMap结构。

二级缓存整合redis

上面我们介绍了 mybatis自带的二级缓存,但是这个缓存是单服务器工作,无法实现分布式缓存。 那么什么是分布式缓存呢?假设现在有两个服务器1和2,用户访问的时候访问了1服务器,查询后的缓存就会放在1服务器上,假设现在有个用户访问的是2服务器,那么他在2服务器上就无法获取刚刚那个缓存,如下图所示:

image.png

为了解决这个问题,就得找一个分布式的缓存,专门用来存储缓存数据的,这样不同的服务器要缓存数据都往它那里存,取缓存数据也从它那里取,如下图所示:

image.png

如上图所示,在几个不同的服务器之间,我们使用第三方缓存框架,将缓存都放在这个第三方框架中, 然后无论有多少台服务器,我们都能从缓存中获取数据。

这里我们介绍mybatis与redis的整合。刚刚提到过,mybatis提供了一个eache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。

mybatis本身默认实现了一个,即PerpetualCache,但是这个缓存的实现无法实现分布式缓存,所以我们要自己来实现。redis分布式缓存就可以,mybatis提供了一个针对cache接口的redis实现类,该类存在mybatis-redis包中实现。

整合步骤1:引入MyBAatis与Redis整合的依赖,如下

 

整合步骤2:在Mapper.xml指定MyBatis二级缓存的实现类

 

或者使用注解方式指明,在IUserMapper接口中指明如下

 

整合步骤3:在resource目录下创建redis.properties文件(为什么一定要叫这个文件名,在后续分析RedisCache源码会讲到

 

整合步骤4:测试

 

RedisCache源码分析

RedisCache和大家普遍实现Mybatis的缓存PerpetualCache方案大同小异,无非是实现Cache接口,并使用jedis操作缓存;不过该项目在设计细节上有一些区别;

 

RedisCache在mybatis启动的时候,由MyBatis的CacheBuilder创建,创建的方式很简单,就是调用RedisCache的带有String参数的构造方法,即RedisCache(String id);而在RedisCache的构造方法中,调用了 RedisConfigurationBuilder 来创建RedisConfig 对象,并使用 RedisConfig 来创建JedisPool。RedisConfig类继承JedisPoolConfig,并提供了 host,port等属性的包装,简单看一下RedisConfig的属性:

image.png

RedisConfig对象是由RedisConfigurationBuilder创建的,简单看下这个类的主要方法:

image.png

image.png

 

查看redisPropertiesFilename属性发现就是指定加载resource目录下的redis.properties文件

image.png

接下来,就是RedisCache使用RedisConfig类创建完成edisPool;在RedisCache中实现了一个简单的模板方法,用来操作Redis:

 

接下来看看Cache中最重要的两个方法:putObject和getObject,通过这两个方法来查看mybatis-redis储存数据的格式为Hash类型

 

可以很清楚的看到,mybatis-redis在存储数据的时候,是使用的hash结构,把cache的id作为这个hash的key (cache的id在mybatis中就是mapper的namespace);这个mapper中的查询缓存数据作为 hash的field,需要缓存的内容直接使用SerializeUtil存储,SerializeUtil和其他的序列化类差不多,负责对象的序列化和反序列化;

Mybatis插件

插件简介

一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作。以MyBatis为例,我们可基于MyBati s插件机制实现分页、分表,监控等功能。由于插件和业务无关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能。

Mybatis插件介绍

Mybati s作为一个应用广泛的优秀的ORM开源框架,这个框架具有强大的灵活性,在四大组件(ExecutorStatementHandlerParameterHandlerResultSetHandler)处提供了简单易用的插 件扩展机制。Mybatis对持久层的操作就是借助于四大核心对象。MyBatis支持用插件对四大核心对象进 行拦截,对mybatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象。

image.png

MyBatis所允许拦截的方法如下

  • 执行器Executor (update、query、commit、rollback等方法);
  • SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
  • 参数处理器ParameterHandler (getParameterObject、setParameters方法);
  • 结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);

Mybatis插件原理

在四大对象创建的时候

  • 1、每个创建出来的对象不是直接返回的,而是interceptorChain.pluginAll(parameterHandler);
  • 2、获取到所有的Interceptor (拦截器)(插件需要实现的接口);调用 interceptor.plugin(target);返回 target 包装后的对象
  • 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP (面向切面)我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行;

插件具体是如何拦截并附加额外的功能的呢?以ParameterHandler来说

 

interceptorChain保存了所有的拦截器(interceptors),是mybatis初始化的时候创建的。调用拦截器链中的拦截器依次的对目标进行拦截或增强。

interceptor.plugin(target)中的target就可以理解为mybatis中的四大对象。返回的target是被重重代理后的对象,如果我们想要拦截Executor的query方法,那么可以这样定义插件:

 

除此之外,我们还需将插件配置到sqlMapConfig.xm l中。

 

这样MyBatis在启动时可以加载插件,并保存插件实例到相关对象(InterceptorChain,拦截器链) 中。待准备工作做完后,MyBatis处于就绪状态。我们在执行SQL时,需要先通过DefaultSqlSessionFactory 创建SqlSession。Executor 实例会在创建 SqlSession 的过程中被创建, Executor实例创建完毕后,MyBatis会通过JDK动态代理为实例生成代理类。这样,插件逻辑即可在 Executor相关方法被调用前执行。

以上就是MyBatis插件机制的基本原理

自定义插件

Mybatis 插件接口-Interceptor

  • Intercept方法,插件的核心方法
  • plugin方法,生成target的代理对象
  • setProperties方法,传递插件所需参数
 

在sqlMapConfig.xml配置插件如下:

 

插件源码分析

Plugin实现了 InvocationHandler接口,因此它的invoke方法会拦截所有的方法调用。invoke方法会 对所拦截的方法进行检测,以决定是否执行插件逻辑。该方法的逻辑如下:

 

invoke方法的代码比较少,逻辑不难理解。首先,invoke方法会检测被拦截方法是否配置在插件的@Signature注解中,若是,则执行插件逻辑,否则执行被拦截方法。插件逻辑封装在intercept中,该方法的参数类型为Invocationo Invocation主要用于存储目标类,方法以及方法参数列表。下面简单看一下该类的定义

 

关于插件的执行逻辑就分析结束

pageHelper分页插件

MyBati s可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据

开发步骤:

  • ① 导入通用PageHelper的坐标
  • ② 在mybatis核心配置文件中配置PageHelper插件
  • ③ 测试分页数据获取

①导入通用PageHelper坐标

 

② 在mybatis核心配置文件中配置PageHelper插件

 

③ 测试分页代码实现

 

数据权限插件

 

通用 mapper

什么是通用Mapper

通用Mapper就是为了解决单表增删改查,基于Mybatis的插件机制。开发人员不需要编写SQL,不需要在DAO中增加方法,只要写好实体类,就能支持相应的增删改查方法。

如何使用通用Mappe?

  1. 首先在maven项目,在pom.xml中引入mapper的依赖
 
  1. Mybatis配置文件中完成配置
 
  1. 实体类设置主键
 
  1. 定义通用mapper
 
  1. 测试
小讯
上一篇 2024-12-25 11:16
下一篇 2024-12-29 12:21

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/2403.html