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

1.回顾Mybatis执行sql的流程

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

接口的定义:
sql

调用接口的实现类方法:
数据库

最后才是调用真正的sql:
session

上面的代码是在接口实现类里面本身去执行id,查找并执行mapper文件里面的sql,那么咱们想是否是能够减小一步呢?mybatis

若是咱们不用本身实现接口,只须要将接口的名字和mapper文件的namespace对应起来,将接口里面的方法名与sql语句标签的id对应起来是否是就能够了呢?app

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

2.mapper动态代理怎么写?

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

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

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

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

咱们在前面还写到过一个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

【做者简介】
秦怀,公众号【秦怀杂货店】做者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界但愿一切都很快,更快,可是我但愿本身能走好每一步,写好每一篇文章,期待和大家一块儿交流。

此文章仅表明本身(本菜鸟)学习积累记录,或者学习笔记,若有侵权,请联系做者核实删除。人无完人,文章也同样,文笔稚嫩,在下不才,勿喷,若是有错误之处,还望指出,感激涕零~

相关文章
相关标签/搜索