秦怀杂货店

General Store

  • 首页
  • 文章归档
  • 标签
  • 分类
  • 关于页面

  • 搜索
随便聊聊 数据结构 小游戏 数据库 Docker Springboot 系统设计 雪花算法 分布式 海量ip 最长回文子串 算法 面试题 线程池 多线程 线程 java学习 布隆过滤器 github 架构设计 docsify Git JVM LeetCode 杂货思考 设计模式 Lambda native isAssignableFrom 反射 剑指Offer mybatis SPI JDBC 编程工具 Java基础 集合

Mybatis【11】-- Mybatis Mapper动态代理怎么写?

发表于 2020-12-26 | 分类于 Mybatis | 0 | 阅读次数 285
  • 1.回顾Mybatis执行sql的流程
  • 2.mapper动态代理怎么写?
  • 3.mapper动态代理怎么做的?

1.回顾Mybatis执行sql的流程

在之前的代码中我们的运行过程再梳理一下,首先我们执行Test,调用dao接口方法

接口的定义:

调用接口的实现类方法:

最后才是调用真正的sql:

上面的代码是在接口实现类里面自己去执行id,查找并执行mapper文件里面的sql,那么我们想是不是可以减少一步呢?

如果我们不用自己实现接口,只需要将接口的名字和mapper文件的namespace对应起来,将接口里面的方法名与sql语句标签的id对应起来是不是就可以了呢?

事实上,mybatis提供了这样的做法,这就是mapper动态代理。

2.mapper动态代理怎么写?

首先主配置文件(Mybatis.xml),在里面配置数据库连接信息,注册需要扫描的mapper文件:

定义数据库查询的接口,里面每一个接口的名字很重要,需要和mapper里面每一条sql对应起来:

定义mapper文件(namespace是接口的全限定类名):

那我们在使用的时候,需要使用sqlSession.getMapper()方法,里面传入的是接口,意思是通过接口的全限定名,也就是前面在mapper.xml文件里面配置的命名空间nameSpace,这样一来,就是获取到了代理类,将dao和mapper.xml文件关联起来了,而每条sql的id与我们的接口方法名字对应起来)

我们在前面还写到过一个selectStudentMap()方法,但是里面调用的是和SelectList()一样的sql,在接口的实现类里面我们自己处理了一下,但是现在使用自动实现的话,底层只会调用SelectOne()或者SelectList()方法,所以这个方法会报错,如果接受类型是list,那么框架会自动使用selectList()方法,否则就会选择selectOne()这个方法。

在这里我们使用的是返回的是map,所以自动选择返回selectOne()方法,那么就会报错。如果我们需要使用自动返回map的话,可以自己定一个map,或者返回list之后再处理,这个知识点后面再介绍,有兴趣可以访问:mybatis的mapper返回map结果集

3.mapper动态代理怎么做的?

打一个断点在sqlSession.getMapper()方法上:

我们可以看到执行下面的接口方法(接口SqlSession的方法)

<T> T getMapper(Class<T> var1);

这是一个接口,我们可以看到实现接口的有两个类,一个是DefaultSqlSession,一个是SqlSessionManager,我们需要看的是DefaultSqlSession下面的接口:

 public <T> T getMapper(Class<T> type) {
    return this.configuration.getMapper(type, this);
  }

我们知道,在创建sqlsession的时候,confiiguration这个配置对象已经创建完成。跟进去,这是使用mapper注册器对象的getMapper()方法,将当前的sqlSession对象传递进去:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

我们跟进去源码,可以发现里面使用knownMappers.get(type)来获取mapper代理工厂,这个konwnMappers是一个hashMap,这个hashMap里面已经初始化了mapperProxyFactory对象了,获取到工厂对象之后,再去使用sqlSession实例化:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    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);
    }
  }

实例化的时候,使用了mapper动态代理:

public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

从下面的debug结果中我们可以看到,这是动态代理的结果,我们看到的是dao,但是动态代理对这个dao做了增强,实则是一个mapperProxy。

【作者简介】:
秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界希望一切都很快,更快,但是我希望自己能走好每一步,写好每一篇文章,期待和你们一起交流。

此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者核实删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

  • 本文作者: 秦怀杂货店
  • 本文链接: http://aphysia.cn/archives/mybatis11
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 随便聊聊 # 数据结构 # 小游戏 # 数据库 # Docker # Springboot # 系统设计 # 雪花算法 # 分布式 # 海量ip # 最长回文子串 # 算法 # 面试题 # 线程池 # 多线程 # 线程 # java学习 # 布隆过滤器 # github # 架构设计 # docsify # Git # JVM # LeetCode # 杂货思考 # 设计模式 # Lambda # native # isAssignableFrom # 反射 # 剑指Offer # mybatis # SPI # JDBC # 编程工具 # Java基础 # 集合
LeetCode【1】-- 两数之和
剑指Offer【32】-- 将数组排成最小的数
  • 文章目录
  • 站点概览
秦怀杂货店

秦怀杂货店

纵然缓慢,驰而不息。

145 日志
19 分类
37 标签
Github E-mail
Creative Commons
0%
© 2022 秦怀杂货店
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4