Mybatis Annotation使用小结

时间:2023-01-03 15:47:02

Mybatis Annotation使用小结

之前一直有看过mybatis的注解使用方式,但没有去看过它的原理。今天看springboot-mybatis-annotation使用的时候,debug了下看了它的加载过程。

  1. 先编写一个示例接口

    @Mapper // 标志为 Mybatis 的 Mapper
    public interface CityDao { /**
    * 根据城市名称,查询城市信息
    *
    * @param cityName 城市名
    */
    @Select("SELECT * FROM city")
    // 返回 Map 结果集
    @Results({
    @Result(property = "id", column = "id"),
    @Result(property = "provinceId", column = "province_id"),
    @Result(property = "cityName", column = "city_name"),
    @Result(property = "description", column = "description"),
    })
    City findByName(@Param("cityName") String cityName);
    }
  2. springboot引入mybatis-spring-boot-starter依赖

    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>${mybatis-spring-boot}</version>
    </dependency>

    它会自动注入MybatisAutoConfiguration这个bean然后解析执行AutoConfiguredMapperScannerRegistrar这个ImportBeanDefinitionRegistrar,它的registerBeanDefinitions方法会扫描包把带有Mapper注解的接口注入到spring容器,并且在内部修改BeanDefinition的class为MapperFactoryBean,并且设置它的自动注入模式为AUTOWIRE_BY_TYPE,实现了SqlSessionFactory的自动注入。

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { logger.debug("Searching for mappers annotated with @Mapper"); ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); try {
    if (this.resourceLoader != null) {
    scanner.setResourceLoader(this.resourceLoader);
    } List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
    if (logger.isDebugEnabled()) {
    for (String pkg : packages) {
    logger.debug("Using auto-configuration base package '{}'", pkg);
    }
    } scanner.setAnnotationClass(Mapper.class);
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(packages));
    } catch (IllegalStateException ex) {
    logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
    }
    }
  3. MapperFactoryBean的实例化

    MapperFactoryBean继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承了DaoSupport,DaoSupport它实现了InitializingBean,所以实例化MapperFactoryBean的时候会调用afterPropertiesSet方法。
    	   @Override
    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
    // Let abstract subclasses check their configuration.
    checkDaoConfig(); // Let concrete implementations initialize themselves.
    try {
    initDao();
    }
    catch (Exception ex) {
    throw new BeanInitializationException("Initialization of DAO failed", ex);
    }
    }

    这里会调用MapperFactoryBean的重写方法checkDaoConfig

      protected void checkDaoConfig() {
    super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
    try {
    configuration.addMapper(this.mapperInterface);
    } catch (Exception e) {
    logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
    throw new IllegalArgumentException(e);
    } finally {
    ErrorContext.instance().reset();
    }
    }
    }
	  因为配置了方法注解所以我们在不配置xml的时候configuration里并没有对应的mapperRegistry,所以会调用configuration的addMapper方法,内部会调用mapperRegistry的addMapper方法

	```
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
``` 从以上代码可知通过MapperAnnotationBuilder这个类去解析当前接口的方法上的配置信息转化成MappedStatement并设置到全局的Configuration里面。这样就和直接解析xml配置达到了一样的效果。 4. MapperFactoryBean生成的动态代理bean的调用 MapperFactoryBean生成的动态代理bean,调用方法的过程最终会委派给MapperProxy的invoke方法,后续的调用过程就和xml解析出来的配置一致了,也就是说不管是注解配置还是xml配置只是解析配置的方式不同,最终都会设置到Configuration里面。然而调用过程一致。 ---
代码下载参考[springboot-learning-example](https://github.com/yaojf/springboot-learning-example)

Mybatis Annotation使用小结的更多相关文章

  1. Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司需要人.产品.业务和方向,方向又要人.产品.业务和方向,方向… 循环』 本文提纲一. ...

  2. MyBatis之级联小结

    在这之前我们知道了MyBatis为我们提供了三种级联:一对一关系(assocation).一对多关系(collection).鉴别器(discriminator).在最后一个鉴别器例子中,看到了当层级 ...

  3. MyBatis动态SQL小结

    6:用于实现动态sql的元素及其用法 if+set--完成更新操作 if+where --完成多条件查询 if+完成多条件查询(替代where)或完成更新操作(替代set) choose(when,o ...

  4. SQL mybatis动态查询小结

    动态返回mysql某张表指定列的名字 <select id="queryColumns" resultType="map" parameterType=& ...

  5. 【mybatis annotation】数据层框架应用--Mybatis(二) 基于注解实现数据的CRUD

    使用MyBatis框架进行持久层开发 MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架. MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索. MyBa ...

  6. MyBatis注解Annotation介绍及Demo

     MyBatis注解Annotation介绍及Demo 2014-04-21 17:09:55 标签:Mybatis Annotation 注解 ResultMap SqlBuilder 原创作品,允 ...

  7. MyBatis Tutorial – CRUD Operations and Mapping Relationships – Part 1---- reference

    http://www.javacodegeeks.com/2012/11/mybatis-tutorial-crud-operations-and-mapping-relationships-part ...

  8. mybatis通用DAO

    扫扫关注"茶爸爸"微信公众号 坚持最初的执着,从不曾有半点懈怠,为优秀而努力,为证明自己而活. 回复:茶爸爸了解他这个人!! 花了几天的时间研究了一下mybatis的源代码,觉得这 ...

  9. MyBatis浅尝笔记

    MyBatis应属于一种轻量级的java持久层技术,它通过简单的SQL xml或注解,将数据库数据映射到接口与POJO.最近项目要用到mybatis,所以学习之后在这里做个总结,文中的示例以xml配置 ...

随机推荐

  1. Resources&period;Load加载文件返回null的原因

    1.文件夹都要放在Resources目录下 2.加载时photoName不需要扩展名 Texture2D t = Resources.Load<Texture2D>("Loadi ...

  2. 检索 COM 类工厂中 CLSID 为 &lbrace;28E68F9A-8D75-11D1-8DC3-3C302A000000&rcub; 的组件失败,原因是出现以下错误&colon; 80040154 没有注册类 &lpar;异常来自 HRESULT&colon;0x80040154 &lpar;REGDB&lowbar;E&lowbar;CLASSNOTREG&rpar;&rpar;

    Resvr32 .net中引用控件的名称 如果注册成功,问题不在出现 但是如果是在x64位的系统中,即使控件注册成功,错误依照提示,是因为大多数第三方写的COM控件,只支持32位的系统, 在VS中找到 ...

  3. mysql添加外键

    语法:alter table 表名 add constraint FK_ID foreign key(你的外键字段名) REFERENCES 外表表名(对应的表的主键字段名); 例: alter ta ...

  4. 当kfreebsd 用户遇见openSUSE系统

    openSuse的系统工具集覆盖了四大主流桌面环境,是针对每一种桌面环境定制的独立的桌面体验.

  5. 为什么arcgis里,鼠标的图标都变成放大镜不能用了

    做作业做到一半,鼠标的图标就只有放大镜了,不管是点箭头还是作图工具都没用,手抓的也没用,只剩下放大镜的功能和图标了,这是怎么一回事啊?种情况我碰到过几次,具体原因不清楚,但是解决方法是有的:把你的数据 ...

  6. 转: Linux 技巧:让进程在后台可靠运行的几种方法

    我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败.如何让命令提交后不受本地关闭终端窗口/网络断开 ...

  7. CodeForces 605A Sorting Railway Cars 思维

    早起一水…… 题意看着和蓝桥杯B组的大题第二道貌似一个意思…… 不过还是有亮瞎双眼的超短代码…… 总的意思呢…… 就是最长增长子序列且增长差距为1的的…… 然后n-最大长度…… 这都怎么想的…… 希望 ...

  8. javascript 数组合并

    javascript 中两个数组合并,当然可以遍历其中一个数组,通过push()方法将元素插入到另一个数组中. 另外,也可以使用内置的方法(javascript Array 对象上就具有的方法,或许比 ...

  9. &lbrack;数据库锁机制&rsqb; 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析

    前言: 在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数据库都提供了锁机制,并引入了事务隔离级别的概念.数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务 ...

  10. CURLOPT&lowbar;RETURNTRANSFER

    curl_setopt($ch,CURLOPT_RETURNTRANSFER,);//设置返回值不直接输出,例如返回xml格式,会将xml原样输出