zoukankan      html  css  js  c++  java
  • MyBatis SpringBoot 杂记

    最近接了个xxx代码.

    不能说人家不好, 因为必进年月久了.能用这么长时间, 不就说明还不错么?! 我们现在每天写的, 能超出人家的么~~~ 呵呵

    Java项目中, 把动态数据源切换的框架整合进来. 嗯...这个有好有不好吧.

    按Service层使用AOP来切换主从. 但是企业应用非常复杂. 如果再加一个别的数据库连接进来, 框架就显得不够用.

    而框架的修改权又掌握在某一个部门手中, 所以,只能类似补丁地融入. 所以有了这一上午走读Spring/MyBatis的机会. 也挺好.

    SpringBoot的一个annotation @SpringBootApplication, 使用其 exclude, 把框架中的某一些 @Configuration 排除掉.

    然后自己写子类继承这些原有的@Configuration类, 并且加上@Configuration.
    然后就可以初始化了.
    原有容器初始化的时候, 以@Bean的方式生产了SqlSessionFactory, 默认执行Mapper的时候就会使用.
    所以,如果用新加进来的DataSource也生成@Bean SqlSessionFactory, 那么Mapper就会迷茫,因为默认是按类型查找SqlSessionFactory.
    解决这个问题, 改框架动静太大. 简单一点, 把原来的@Bean SqlSessionFactory加上@Primary,为默认.
    
    然后新数据库连接使用的时候,可以使用
    @Autowired @Quirified("xxx") 来注入SqlSessionFactory, 然后在@PostConstruct里, 把SqlSessionTemplate获取到,
    然后,可以使用 sqlSessionTemplate.getMapper(Xxx.class) 获取到 Mapper.class接口的代理实例.
    在这里踩了一个坑, 就是 getMapper总是说没有注册. 于是追踪了一下Mapper的注册过程.
    
    有几篇blog写得挺好. 但是太冗长
    Mybatis初始化加载流程————配置文件解析 https:
    //blog.csdn.net/u011043551/article/details/80607050
    Mybatis 源码学习(一) Mapper 注册
    https://blog.csdn.net/tiantiandjava/article/details/80569451

    Mybatis初始化加载流程————Mapper接口注册
    https://blog.csdn.net/u011043551/article/details/80619319
    关键点: SqlSessionFactoryBean 是建造者模式, 设置了一堆属性之后, 然后调用 getObject()的时候, 执行 afterPropertiesSet();-->buildSqlSessionFactory(); --> 一大段. 这大段代码的基本逻辑有3点: 1.注册Class, 基本上是Example, DTO 等等. 2.注册plugins, 比如翻页插件就在这里注册 3.注册handler, 这一段没特别了解, 后面用到再看看 4.注册xml, xmlConfigBuilder.parse() 这一段包含了这次的内容. 一大段. private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } 基本是解析xml各个节点. 其中mapperElement 这个方法里, 把xml节点中mapper 进行解析.调用mapperParser.parse();(XMLMapperBuilder) ---> bindMapperForNamespace(); private void bindMapperForNamespace() { String namespace = builderAssistant.getCurrentNamespace(); if (namespace != null) { Class<?> boundType = null; try { boundType = Resources.classForName(namespace); } catch (ClassNotFoundException e) { //ignore, bound type is not required } if (boundType != null) { if (!configuration.hasMapper(boundType)) { // Spring may not know the real resource name so we set a flag // to prevent loading again this resource from the mapper interface // look at MapperAnnotationBuilder#loadXmlResource configuration.addLoadedResource("namespace:" + namespace); configuration.addMapper(boundType); } } } } 会把xml中namespace中写着的xxx.xxx.Mapper认为是类, 来加载注册!!! 藏得真是深.

    参考了:
    Spring读取mybatis在多个jar包下的的mapper文件
    https://blog.csdn.net/zixuan0104/article/details/54601563

    primary这个翻译过来是 首要的,首选的意思。
    primary的值有true和false两个可以选择。默认为false。
    当一个bean的primary设置为true,然后容器中有多个与该bean相同类型的其他bean,
    此时,当使用@Autowired想要注入一个这个类型的bean时,就不会因为容器中存在多个该类型的bean而出现异常。而是优先使用primary为true的bean。
    不过,如果容器中不仅有多个该类型的bean,而且这些bean中有多个的primary的值设置为true,那么使用byType注入还是会出错。

    https://blog.csdn.net/qq_36951116/article/details/79130591

    https://www.cnblogs.com/dongying/p/4142476.html

    希望Mapper自动分了数据源, 需要在MapperScan上加上ref

    @MapperScan(basePackages="com.XXX.bpaas.idm.mapper.dao", sqlSessionTemplateRef = "idmSqlSessionTemplate")

    @MapperScan(basePackages="com.XXX.bpaas.idm.mapper.dao", sqlSessionFactoryRef = "xxxFactory"), 这样就可以在注册每个Mapper的时候,匹配到正确的数据源.

    主从切换的数据源是在线程切换层次, 不会影响到这里.

    MapperScan决定xxxMapper.select 使用 那个xxxxFactory, 执行时, 如果该数据源有主从切换,读写分离,在ThreadLocak<Holder>中切换变量值就OK了.

    >>参照了

    https://blog.csdn.net/mxw2552261/article/details/78640062   good

    https://blog.csdn.net/weixin_40562217/article/details/82840764   good

    https://www.cnblogs.com/dongying/p/4142476.html

    https://www.cnblogs.com/dongying/p/4040435.html

    下一步研究一下, 事务传播, 两个数据源的@Transactional 嵌套时有什么问题.

    https://www.cnblogs.com/Kidezyq/p/8541199.html    采坑

    https://www.cnblogs.com/zishengY/p/6850673.html   多个事务管理器

  • 相关阅读:
    Python之协程
    Python之线程 3
    js和jsp之间相互传值
    毕业设计记录
    毕业设计记录16
    mysql select一张表的字段数据insert写入另一张表,同时传入自定义数据
    MySQL防止重复插入相同记录
    毕业设计记录
    解决python mysql插入int型数据报错:TypeError: %d format: a number is required, not str
    毕业设计记录
  • 原文地址:https://www.cnblogs.com/tekikesyo/p/10346555.html
Copyright © 2011-2022 走看看