MyBatis是如何让我们通过接口就能调用到SQL的

简介: MyBatis是如何让我们通过接口就能调用到SQL的

大致可分为如下几个步骤

1. 动态注册bean

1.1 根据配置mapperScan, 扫描对应的包, 将对应的类解析成BeanDefinition
1.2 通过替换BeanDefinition中的BeanClass为MapperFactoryBean, (原来的BeanClass是Mapper接口) 实现了在spring生成对应的对象时,  返回的对象不是本身类型的对象,而是MapperFactoryBean重写FactoryBean接口的getObject()方法返回的代理对象。该方法getObject()已经对mapper接口进行了代理,  即后续进行自动注入时, 也是返回getObject()生成的代理对象

2. 生成对应的代理对象

2.1 在getObject()方法中, 会获取到接口的全限定名称, 然后进一步对代理方法进行封装, 调用链如下
MapperFactoryBean: 
        public T getObject() throws Exception {
          return getSqlSession().getMapper(this.mapperInterface);
        }
       DefaultSqlSession: 
           public <T> T getMapper(Class<T> type) {
            //configuration是mybatis的重要配置类, 在初始化的时候, 就会将mapper接口添加到configuration中
            return configuration.getMapper(type, this);
           }
       Configuration: 
        public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          return mapperRegistry.getMapper(type, sqlSession);
        }
       MapperRegistry: 
        public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
            //获取mapper代理工厂
          final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
          if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
          }
          try {
            return mapperProxyFactory.newInstance(sqlSession);
          } catch (Exception e) {
            throw new BindingException("Error getting mapper instance. Cause: " + e, e);
          }
        }
       MapperProxyFactory: 
        protected T newInstance(MapperProxy<T> mapperProxy) {
          return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
        }
        public T newInstance(SqlSession sqlSession) {
          //返回一个新代理对象
          final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
          return newInstance(mapperProxy);
        }


2.2 在org.apache.ibatis.binding.MapperProxy#cachedInvoker中, new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())), 并且将代理方法调用器缓存起来. MapperMethod该对象即是最终调用方法的对象.

3. 执行对应的方法

3.1 方法调用, 代理里最常见的方法invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          //过滤掉object的方法
          if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
          } else {
            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      }


3.2. org.apache.ibatis.binding.MapperProxy.PlainMethodInvoker重写的invoke方法中,判断该方法是否被调用过(是否存在于缓存), 若没有, 则创建一个PlainMethodInvoker方法调用器, 传入MapperMethod(MapperMethod是真正执行方法的对象), 并将新创建的PlainMethodInvoker存入缓存中(methodCache), 并调用该PlainMethodInvoker的invoke方法,
3.3. xml中的id和select等标签封装成了SqlCommand, 调用mapperMethod的execute, 执行对应的增删改查.

4. 结果集封装, 进行一些数据库数据对应java对象的转换

通过mybatis的封装和代理, 将mapper.xml转换成了接口的实例对象

如有谬误, 欢迎斧正

简化版如下: https://blog.csdn.net/sinat_25991865/article/details/89891581

public interface UserMapper {
  List<SysUser> selectAll();
}


public class MyMapperProxy<T> implements InvocationHandler {
  private Class<T> mapperInterface;
  private SqlSession sqlSession;
  public MyMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
      this.mapperInterface = mapperInterface;
      this.sqlSession = sqlSession;
  }
  @Override
  public Object invoke(Object proxy , Method method , Object[] args)
      throws Throwable {
    //针对不同的 sql 类型,需要调用sqlSession不同的方法
    //接口方法中的参数也有很多情况 ,这里只考虑没有有参数的情况
    List<T> list= sqlSession.selectList(
        mapperInterface.getCanonicalName() + ”.” + method.getName());
    //返回数据也有很多情况,这里不做处理直接返回
    return list;
  }
}


方法调用

//获取sqlSession
SqlSession sqlSession = getSqlSession();
//获取 UserMapper 接口
MyMapperProxy userMapperProxy = new MyMapperProxy(
    UserMapper.class , sqlSession) ;
UserMapper userMapper = (UserMapper) Proxy.newProxyinstance (
    Thread.currentThread().getContextClassLoader(),
    new Class[ ] {UserMapper.class},
    userMapperProxy) ;
//调 用 selectAll 方 法
List<SysUser> user= userMapper.selectAll();


目录
相关文章
|
2月前
|
SQL XML Java
通过MyBatis的XML配置实现灵活的动态SQL查询
总结而言,通过MyBatis的XML配置实现灵活的动态SQL查询,可以让开发者以声明式的方式构建SQL语句,既保证了SQL操作的灵活性,又简化了代码的复杂度。这种方式可以显著提高数据库操作的效率和代码的可维护性。
164 18
|
7月前
|
SQL Java 数据库连接
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
|
6月前
|
SQL Java 数据库连接
MyBatis动态SQL字符串空值判断,这个细节99%的程序员都踩过坑!
本文深入探讨了MyBatis动态SQL中字符串参数判空的常见问题。通过具体案例分析,对比了`name != null and name != &#39;&#39;`与`name != null and name != &#39; &#39;`两种写法的差异,指出后者可能引发逻辑混乱。为避免此类问题,建议在后端对参数进行预处理(如trim去空格),简化MyBatis判断逻辑,提升代码健壮性与可维护性。细节决定成败,严谨处理参数判空是写出高质量代码的关键。
722 0
|
2月前
|
SQL Java 数据库连接
SSM相关问题-1--#{}和${}有什么区别吗?--Mybatis都有哪些动态sql?能简述一下动 态sql的执行原理吗?--Spring支持的几种bean的作用域 Scope
在MyBatis中,`#{}`是预处理占位符,可防止SQL注入,适用于大多数参数传递场景;而`${}`是直接字符串替换,不安全,仅用于动态表名、列名等特殊场景。二者在安全性、性能及使用场景上有显著区别。
61 0
|
5月前
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
370 5
|
7月前
|
SQL Java 数据库连接
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错
|
7月前
|
SQL 缓存 Java
框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性
本文详细解构了MyBatis的工作机制,包括解析配置、创建连接、执行SQL、结果封装和关闭连接等步骤。文章还介绍了MyBatis的五大核心功能特性:支持动态SQL、缓存机制(一级和二级缓存)、插件扩展、延迟加载和SQL注解,帮助读者深入了解其高效灵活的设计理念。
|
8月前
|
SQL XML Java
九、MyBatis动态SQL
九、MyBatis动态SQL
94 2
|
7月前
|
人工智能 Java 数据库连接
MyBatis Plus 使用 Service 接口进行增删改查
本文介绍了基于 MyBatis-Plus 的数据库操作流程,包括配置、实体类、Service 层及 Mapper 层的创建。通过在 `application.yml` 中配置 SQL 日志打印,确保调试便利。示例中新建了 `UserTableEntity` 实体类映射 `sys_user` 表,并构建了 `UserService` 和 `UserServiceImpl` 处理业务逻辑,同时定义了 `UserTableMapper` 进行数据交互。测试部分展示了查询、插入、删除和更新的操作方法及输出结果,帮助开发者快速上手 MyBatis-Plus 数据持久化框架。
488 0
|
7月前
|
SQL XML Java
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
177 0

热门文章

最新文章