首页 - 通讯 - Mybatis-Plus实现单表CRUD原理

Mybatis-Plus实现单表CRUD原理

2023-10-10 09:11

介绍

越来越多的人在使用Mybatis-plus。基本上无需编写代码即可完成单表的增删改查。使用时我们只需要从原来的Mapper接口文件继承BaseMapper即可自动完成单表的CRUD。之前一直在用,从来没有想过如何实现。经过一下午的时间,我大致了解了Mybatis-plus是如何实现通用单表CRUD的。

示例

在讲原理之前,我们先简单了解一下Mybatis是如何实现查询的。示例代码如下:

@Slf4j
public class MybatisApp {
    公共 静态 void main(字符串[] args) 投掷 IOException {
        字符串资源 = "mybatis-config. xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory 工厂= new  SqlSessionFactoryBuilder().build(inputStream);

        尝试 (SqlSession session = factory.openSession()) {
            UserEntity user = (UserEntity) www.gsm-guard.netOne("com.buydeem.mapper.UserMapper.getById", 1);
            www.gsm-guard.net("{}",用户);
        }
    }
}
  • mybatis-config.xml配置文件

配置
        PUBLIC "-//www.gsm-guard.net//DTD Config 3.0/ /CN"
        "https:// www.gsm-guard.net/dtd/mybatis-3-config.dtd">
<配置>
    < 属性 资源="jdbc.properties">
    属性>
    <设置>
        <设置 名称="mapUnderscoreToCamelCase"  值=“真”/>
    设置>
    <类型别名>
        <包装 名称="com.buydeem.entity"/>
    类型别名>
     <环境 默认 =“开发”>
        <环境 id=“发展”>
            < transactionManager 类型="JDBC"/>
            <数据源类型="POOLED">
               <属性  名称=“驱动程序” ="${jdbc.driver}"/>
               <属性 名称="url" ="${jdbc.url}"/>
                <属性 姓名="用户名" ="${jdbc.用户名}"/>
                 <属性 名称= "密码" ="${jdbc.password}"/>
            数据源>
        环境>
    环境>

    <映射器>
        < 映射器 资源="mapper/UserMapper.xml"/>
    映射器>

< /配置>
  • UserMapper.xml文件

映射器
PUBLIC"-//www.gsm-guard.net//DTD映射器3.0//EN"
    》https: // www.gsm-guard.net/dtd/mybatis-3-mapper.dtd">
<mapper命名空间= “com.buydeem.mapper.UserMapper ” | “getById”结果类型=“用户实体”? 映射器>

示例代码很简单,首先通过读取配置文件创建一个SqlSessionFactory,然后获取SqlSession来执行查询。

配置

通过前面简单的例子,似乎还是不清楚原因。我们先看一下www.gsm-guard.netOne()的实现并跟踪它的源代码。最终实现如下:

  私人  列表 选择列表(字符串语句、对象参数、RowBounds rowBounds、ResultHandler 处理程序){
try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return  executor.query(ms, wrapCollection(参数), rowBounds, 处理程序);
catch (异常 e) {
      抛出 ExceptionFactory.wrapException("错误正在查询数据库。原因:“ + e, e);
最后 {
      ErrorContext.instance().reset();
    }
  }

该方法从配置中获取一个MappedStatement实例,然后将其关联执行器 去执行。

首先我们要分析一下这个配置是个什么东西。在我们的示例代码中,它实际上就是读取mybatis-config.xml配置文件构建出一个配置类。从Configuration的源码中也有体现,这个配置类中的属性与mybatis-config.xml能够回复起来。

 MappedStatement ms = 配置.getMappedStatement(语句

该代码是从MappedStatement实例的Configuration实例中获取,其内部实现如下:

 public MappedStatement getMappedStatement(字符串 id,布尔值 验证日期不完整的陈述) {
if ( validateIncompleteStatements } }

实际上是从 Configuration 中的属性 mappedStatements 获取 MappedStatement 示例。

 受保护 最终映射映射语句 = 新  StrictMap("映射语句集合")
.conflictMessageProducer((savedValue, targetValue) ->
     ”。请检查“ + savingValue.getResource() + ”和“” + targetValue.getResource());

可以看到Configuration中的mappedStatements类型为StrictMap ,它继承了HashMap,并重写了put和get方法。

    public V put(字符串键,V值) {
      if(包含Key(键)){
        抛出 new IllegalArgumentException(名称 + ”已包含 值 “ + key
            + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
      }       if(key.contains( ".")) {
        final String shortKey = getShortName(key);
        if (超级.get (shortKey) == null) {
          super.put(shortKey, 值);
        } 否则 {
           super.put(shortKey, (V) new 歧义(shortKey));
        }
      }       回归 超级 .put(key, value);
    } 
    
    
    公共 V 获取(对象键) {
V值=super.get(key);
      if (value == null) {           IllegalArgumentException(名称+”不包含“+键)的值;
      }
      if (值实例含糊不清){
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " 在“”中不明确 + 姓名
            + ”(尝试使用包含命名空间的全名,或重命名其中一个条目)");
      }
      return值;
    }

MappedStatement

通过前面我们了解到配置内部用一个Map来存储MappedStatement,现在的问题是它什么时候被撤去的。

  public void addMappedStatement(MappedStatement ms)  {
    mappedStatements.put(ms.getId(), ms) ;
  }

配置中,仅提供了一种方法来添加MappedStatement。同时还可以了解一点配置存储MappedStatementMap的key是MappedStatement的ID属性。唯一调用 Configuration.addMappedStatement() 方法的是 MapperBuilderAssistant。从名字就可以看出,这个类是用来构建Mapper的工具类。我们创建的Mapper.xml文件中的sql语句其实就是解析xml文件,然后通过这个工具类将其转换为MappedStatement并存储在Configuration实例中。本文不会详细介绍如何解析xml。如果有兴趣可以自己阅读源码。

现在的问题是这个MappedStatement有什么用?

public final class MappedStatement {

  私有 字符串资源;
  private 配置配置;
  private 字符串id;
  private  整数 fetchSize;
  private 整数超时;
private StatementType statementType;
  privateResultSetType resultSetType;
   私有
 SqlSource sqlSource;
  私有 缓存缓存;
  private ParameterMap parameterMap;
  private 列表结果地图;
  private booleanflushCacheRequired;
私有 booleanuseCache;
  私有 boolean结果已排序;
  privateSqlCommandType sqlCommandType;
  私有 密钥生成器 keyGenerator;
  私有字符串[] keyProperties;
  private String[] keyColumns;
  private boolean hasNestedResultMaps;
private String databaseId;
private 日志语句Log;
private LanguageDriver lang; private String[] resultSets;
}

其实每一个MappedStatement都对应着我们自定义的Mapper接口中的一个方法,它保存了我们定义的SQL语句的配置、参数结构、返回值结构、Mybatis的处理方式等。内容对应于我们的Mapper.xml 中定义的内容。