首页 > 其他分享 >Mybatis设计模式

Mybatis设计模式

时间:2023-05-06 19:34:21浏览次数:41  
标签:log ErrorContext void 接口 Mybatis 设计模式 public String

创建型

建造者模式,工厂模式

我们在单独Mybatis框架执行SQL语句的时候,需要获得SqlSession实例来直接执行已映射的 SQL 语句,在获得SqlSession实例的过程中,就使用了建造者模式和工厂模式。我们来看看一下调用过程:

1 String resource = "org/mybatis/example/mybatis-config.xml";
2 InputStream inputStream = Resources.getResourceAsStream(resource);
3 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
4 
5 try (SqlSession session = sqlSessionFactory.openSession()) {
6   Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
7 }

这里的Resource类使用了简单工厂模式,通过xml配置文件获得输入流,不过今天我想重点介绍一下SqlSessionFactoryBuilder类和SqlSessionFactory接口,他们分别使用了建造者模式和工厂模式。传统的建造者模式有两个重要的角色:建造者和指导者,将责任进行分割,可在实际的使用中往往只有一个建造者类调用重载的build()方法创建对象,建造者模式解决的问题是某些参数可能是可选的,避免被迫定义所有参数创建对象。DefaultSqlSessionFactory类使用了工厂模式,通过不同的配置产生不同的SqlSession类执行SQL语句。

单例模式

ErrorContext是MyBatis中用于记录线程范围内执行环境错误信息的单例对象。每个线程在执行数据库操作时,都会有一个对应的ErrorContext对象来记录当前执行的上下文信息和错误信息。ErrorContext对象被设计成线程范围内的单例,这意味着每个线程只会有一个ErrorContext对象,并且这个对象可以被整个线程共享。在多线程环境下,使用单例模式可以保证每个线程都能够独立地记录自己的执行环境错误信息,能够避免了线程之间信息错误传递。在下面的代码中,ErrorContext有私有的构造方法,同时具有instance()方法提供全局唯一访问点,而且从方法得知这是一个懒汉模式。

ErrorContext部分源码如下:

 1 // 将自身存储进ThreadLocal,从而进行线程间的隔离
 2 private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();
 3 
 4 private ErrorContext() {
 5 }
 6 /**
 7  * 从ThreadLocal取出已经实例化的ErrorContext,或者实例化一个ErrorContext放入ThreadLocal
 8  * @return ErrorContext实例
 9  */
10 public static ErrorContext instance() {
11   ErrorContext context = LOCAL.get();
12   if (context == null) {
13     context = new ErrorContext();
14     LOCAL.set(context);
15   }
16   return context;
17 }

 

结构型

适配器模式

适配器模式可以解决兼容性问题,在Mybatsi的logging包中,有一个Log接口,该接口定义了MyBatis直接使用的日志方法,即目标类。

1 public interface Log {
2     boolean isDebugEnabled();
3     boolean isTraceEnabled();
4     void error(String var1, Throwable var2);
5     void error(String var1);
6     void debug(String var1);
7     void trace(String var1);
8     void warn(String var1);
9 }

 

实现该接口的适配器类有多个,比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。

 1 import org.apache.ibatis.logging.Log;
 2 import org.apache.log4j.Level;
 3 import org.apache.log4j.Logger;
 4 public class Log4jImpl implements Log {
 5     private static final String FQCN = Log4jImpl.class.getName();
 6     private final Logger log;
 7     public Log4jImpl(String clazz) {
 8         this.log = Logger.getLogger(clazz);
 9     }
10     public boolean isDebugEnabled() {
11         return this.log.isDebugEnabled();
12     }
13     public boolean isTraceEnabled() {
14         return this.log.isTraceEnabled();
15     }
16     public void error(String s, Throwable e) {
17         this.log.log(FQCN, Level.ERROR, s, e);
18     }
19     public void error(String s) {
20         this.log.log(FQCN, Level.ERROR, s, (Throwable)null);
21     }
22     public void debug(String s) {
23         this.log.log(FQCN, Level.DEBUG, s, (Throwable)null);
24     }
25     public void trace(String s) {
26         this.log.log(FQCN, Level.TRACE, s, (Throwable)null);
27     }
28     public void warn(String s) {
29         this.log.log(FQCN, Level.WARN, s, (Throwable)null);
30     }
31 }

 

装饰者模式

在MyBatis中,缓存的功能由Cache接口(抽象构件)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(具体构建)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache进行缓存策略的增强。

  • 抽象组件:Cache 接口,定义了缓存接口的基本方法。

  • 具体组件:PerpetualCache 类,实现了 Cache 接口,提供了缓存的基本实现。

  • 具体装饰者:LruCache 类、ScheduledCache 类、LoggingCache 类等,实现了 Cache 类并实现了其抽象方法,提供了具体的缓存增强功能。

 1 public interface Cache {
 2    .........
 3     void putObject(Object var1, Object var2);
 4    ..........
 5 }
 6 
 7 public class PerpetualCache implements Cache {
 8      .......
 9     public void putObject(Object key, Object value) {
10         this.cache.put(key, value);
11     }
12      .......
13 }
14 //在具体装饰类中对具体构件对象进行了功能扩充,在putObject方法中实现了先进先出策略。
15 public class FifoCache implements Cache {
16     private final Cache delegate;
17     private final Deque<Object> keyList;
18     private int size;
19     public FifoCache(Cache delegate) {
20         this.delegate = delegate;
21         this.keyList = new LinkedList();
22         this.size = 1024;
23     }
24     .........
25     public void putObject(Object key, Object value) {
26         this.cycleKeyList(key);
27         this.delegate.putObject(key, value);
28     }
29     .......
30     private void cycleKeyList(Object key) {
31         this.keyList.addLast(key);
32         if (this.keyList.size() > this.size) {
33             Object oldestKey = this.keyList.removeFirst();
34             this.delegate.removeObject(oldestKey);
35         }
36     }
37 }

 

组合模式

Mybatis中的SqlNode是使用组合模式实现的。SqlNode是一个抽象类,它有两个重要的子类:MixedSqlNode和TextSqlNode。MixedSqlNode代表一个混合类型的SqlNode,包含了多个SqlNode,它的作用是将多个SqlNode组合成一个整体,通过递归调用其子节点的apply方法来完成SQL语句的拼接。TextSqlNode代表一个文本类型的SqlNode,它可以包含一个动态的表达式,通过参数的替换来生成最终的SQL语句片段。在解析Mapper XML文件时,Mybatis会将每个SQL语句解析为一个SqlNode树,然后通过递归调用SqlNode的apply方法来遍历整个树,最终将所有的SqlNode组合成一个完整的SQL语句。

代理模式

代理模式可以认为是MyBatis核心使用的模式,在 MyBatis 中,每个 Mapper 接口都需要有一个对应的 Mapper 映射文件,用于描述 SQL 语句以及 SQL 语句与接口方法的映射关系。在运行时,MyBatis 会根据接口定义创建一个代理对象,该代理对象实现了该接口的所有方法,并将方法调用转换为执行对应的 SQL 语句。这里的代理对象就是使用 JDK 动态代理生成的。

行为型

模板方法模式

Executor 是 MyBatis 的核心接口之一,定义了数据库操作的基本方法,其类图如下:

BaseExecutor 类中的 query() 方法会先创建 CacheKey 对象,并根据 CacheKey 对象查找一级缓存,如果缓存命中则返回缓存中记录的结果对象,如果未命中则查询数据库得到结果集,之后将结果集映射成结果对象并保存到一级缓存中,同时返回结果对象。

doUpdate、doFlushStatements、doQuery 和 doQueryCursor 这几个方法就是交由子类来实现的,也就是说继承 BaseExecutor 的子类只需要实现这 4 个基本方法来完成数据库的相关操作即可。

BaseExecutor 的子类有 SimpleExecutor、ReuseExecutor、BatchExecutor类。

  • SimpleExecutor,每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

  • ReuseExecutor,执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。

  • BatchExecutor,将所有sql都添加到批处理中,它缓存了多个Statement对象,等待统一执行(即调用executeBatch()方法后)。

迭代器模式

DefaultCursor 实现了 Cursor 接口,而Cursor接口实现了Iterable接口,Iterable接口中有Iterator方法,DefaultCursor 类定义了一个成员变量 cursorIterator,其类型为 CursorIterator,并在iterator方法中进行返回。而CursorIterator是DefaultCursor 的一个内部类,实现了 JDK 中的 Iterator 接口。

 

标签:log,ErrorContext,void,接口,Mybatis,设计模式,public,String
From: https://www.cnblogs.com/RQfreefly/p/17376761.html

相关文章

  • [设计模式]设计原则
    参考:https://zhuanlan.zhihu.com/p/24614363https://zhuanlan.zhihu.com/p/422737773https://zhuanlan.zhihu.com/p/141459645面向对象设计原则1、开闭原则:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。作用:1......
  • sql注入原理和mybatis解决sql注入
    转载:https://www.bilibili.com/video/BV1ZR4y1Y745/?spm_id_from=333.880.my_history.page.click&vd_source=46d50b5d646b50dcb2a208d3946b1598https://juejin.cn/post/7064740474057146398#heading-11......
  • Mybatis通用DAO设计封装(mybatis)
    关键字:Mybatis通用DAO设计封装(mybatis)说明:mybatis默认分页机制为逻辑分页,所以要处理成物理分页需要自己写一个拦截器(当然也可以不用这个分页机制,自己直接在SQL文件中实现也是可以的)RowBoundsrowBound=newRowBounds(start,pageSize);具体封装如下......
  • mybatis优化
    关键字:mybatis优化1、每个bean都要有对应的get/set方法(因为找不到get方法的话mybatis会按照复杂对象处理)2、使用mybatis.config.xml进行调优,参考如下:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis..org//DT......
  • spring cloud gradle mybatis
    一、引入依赖在build.gradle文件中的dependencies的对象中引入依赖implementation'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4'二、配置数据库及mybatis在application.yml文件中配置数据库spring:datasource:url:jdbc:mysql://192.168.0.1:3306/dbName......
  • mybatis-plus-generator生成代码
    mybatis-plus-generator生成代码依赖包 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.6</version></dependenc......
  • iBatis与MyBatis区别
     iBatis框架的主要优势:1、iBatis封装了绝大多数的JDBC样板代码,使得开发者只需关注SQL本身,而不需要花费精力去处理例如注册驱动,创建Connection,以及确保关闭Connection这样繁杂的代码。2、从iBatis到MyBatis,不只是名称上的变化,MyBatis提供了更为强大的功能,同时并没有损......
  • 自定义mybatis插件之全局数据过滤
    目录一、介绍二、实现三、效果四、源码一、介绍通过开发mybatis的插件来实现对全局的sql查询语句进行拦截,并新增全局的过滤条件做到无感知的数据过滤,比如全局过滤某个租户的数据。二、实现实现思路1、通过mybatis的拦截器拦截所有查询的sql2、使用Druid里面的工具类解析sq......
  • MyBatis 配置详解
    目录mybatis-config.xml核心配置文件1.environments元素1.1子元素environment1.2transactionManager事务管理器(共两种)2.mappers元素(定义映射SQL语句文件)3.properties4.typeAliases(定义别名)其他配置【设置】mybatis-config.xml核心配置文件mybatis-config.xml包含的......
  • Spring整合Mybatis
    1、Spring整合Mybatis思路分析1.1、环境准备在准备环境的过程中,我们也来回顾下Mybatis开发的相关内容:步骤1:准备数据库表Mybatis是来操作数据库表,所以先创建一个数据库及表createdatabasespring_dbcharactersetutf8;usespring_db;createtabletbl_account(id......