转自: https://blog.csdn.net/LOVELONG8808/article/details/78738086


由于项目已经发布到线上,要是修改一个Mapper.xml文件的话,需要重启整个服务,这个是很耗时间的,而且在一段时间内导致服务不可用,严重影响用户的体验度。所以希望可以有一个机制可以,当修改某个mapper.xml的时候,只要重新加载这个mapper.xml就好了,参考网上的一些资料和demo,加上一些自己的总结,下面的代码是通过测试的,可以供你们参考和使用。

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;  import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;  public class RefreshMapperCache {  private Log log  = LogFactory.getLog(RefreshMapperCache.class);  private SqlSessionFactory sqlSessionFactory;  private Resource[] mapperLocations;  private String packageSearchPath;  private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 记录文件是否变化  //记录发生改变的xml文件名称private List<String> changeResourceNameList = new ArrayList<>();public void refreshMapper() {  try {  Configuration configuration = this.sqlSessionFactory.getConfiguration();  // step.1 扫描文件  try {  this.scanMapperXml();  } catch (IOException e) {  log.error("packageSearchPath扫描包路径配置错误");  return;  }  //            System.out.println("==============刷新前mapper中的内容 start===============");
//            //获取xml中的每个语句的名称即 id = "findUserById";
//            for (String name : configuration.getMappedStatementNames()) {
//                System.out.println(name);
//            }
//            System.out.println("==============刷新前mapper中的内容   end===============");  //清空被修改过后的文件名称,确保该集合是空的changeResourceNameList.clear();// step.2 判断是否有文件发生了变化  if (this.isChanged()) {  // step.2.1 清理  this.removeConfig(configuration);  // step.2.2 重新加载  for (Resource configLocation : mapperLocations) {  try { //匹配被修改过的mapper文件,如果存在,则重新加载//如果想要重新加载全部mapper,可以不匹配if(changeResourceNameList.contains(configLocation.getFilename())){XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments());  xmlMapperBuilder.parse();  System.out.println("mapper文件[" + configLocation.getFilename() + "]缓存加载成功");  }} catch (IOException e) {  System.out.println("mapper文件[" + configLocation.getFilename() + "]不存在或内容格式不对");  continue;  }  }//清空被修改过后的文件名称changeResourceNameList.clear();}  //            System.out.println("--------------------------刷新后mapper中的内容 start--------------------------");
//            for (String name : configuration.getMappedStatementNames()) {
//                System.out.println(name);
//            }
//            System.out.println("--------------------------刷新后mapper中的内容  end--------------------------");   } catch (Exception e) {  System.out.println("****************刷新缓存异常: "+e.getMessage());}  }  public void setPackageSearchPath(String packageSearchPath) {  this.packageSearchPath = packageSearchPath;  }  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {  this.sqlSessionFactory = sqlSessionFactory;  }  /** * 扫描xml文件所在的路径 * @throws IOException  */  private void scanMapperXml() throws IOException {  this.mapperLocations = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);  }  /** * 清空Configuration中几个重要的缓存 * @param configuration * @throws Exception */  private void removeConfig(Configuration configuration) throws Exception {  Class<?> classConfig = configuration.getClass();  clearMap(classConfig, configuration, "mappedStatements");  clearMap(classConfig, configuration, "caches");  clearMap(classConfig, configuration, "resultMaps");  clearMap(classConfig, configuration, "parameterMaps");  clearMap(classConfig, configuration, "keyGenerators");  clearMap(classConfig, configuration, "sqlFragments");  clearSet(classConfig, configuration, "loadedResources");  }  @SuppressWarnings("rawtypes")  private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {  Field field = classConfig.getDeclaredField(fieldName);  field.setAccessible(true);  Map mapConfig = (Map) field.get(configuration);  mapConfig.clear();  }  @SuppressWarnings("rawtypes")  private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {  Field field = classConfig.getDeclaredField(fieldName);  field.setAccessible(true);  Set setConfig = (Set) field.get(configuration);  setConfig.clear();  }  /** * 判断文件是否发生了变化 * @param resource * @return * @throws IOException */  private boolean isChanged() throws IOException {  boolean flag = false;  System.out.println("***************************获取文件名   开始************************************");for (Resource resource : mapperLocations) {  String resourceName = resource.getFilename();  System.out.println("resourceName == " + resourceName+",  path = "+resource.getURL().getPath());boolean addFlag = !fileMapping.containsKey(resourceName);// 此为新增标识  // 修改文件:判断文件内容是否有变化  Long compareFrame = fileMapping.get(resourceName);  long lastFrame = resource.contentLength() + resource.lastModified();  boolean modifyFlag = null != compareFrame && compareFrame.longValue() != lastFrame;// 此为修改标识  if(addFlag){System.out.println("            新增了:==="+ resourceName);}if(modifyFlag){System.out.println("            修改了:==="+ resourceName);}// 新增或是修改时,存储文件  if(addFlag || modifyFlag) {  fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件内容帧值  flag = true;  changeResourceNameList.add(resourceName);}  } System.out.println("***************************获取文件名   结束************************************");return flag;  }
}  

写一个实体类,然后在spring中配置改实体类的bean即可

    <bean id="refreshMapperCache" class="com.company.project.util.RefreshMapperCache" >  <!-- 扫描的映射mapper.xml的文件路径这个地方要注意mapper的文件,多数据源情况下,只能扫描自己数据源下的mapper,否则会报异常          --><property name="packageSearchPath" value="classpath*:mapper/trade/**/*.xml"></property><!-- 配置自己的数据源 --><property name="sqlSessionFactory" ref="sqlSessionFactoryPay"></property>  </bean>  

由于我们公司使用的是多数据源,所以在配置bean的时候,要给每个数据源配置一个bean,注意点就是在配置bean的时候

1. 如果是多数据源的情况 ,  扫描mapper.xml文件的时候,只能扫该数据源下的mapper.xml文件

2. 多数据源情况想,设置sqlSessionFactory 的时候,要设置为对应的数据源

3. 如果是但数据源的情况,那么就简单了,只需要配置当前数据源及对应的mapper.xml文件即可

(转)mybatis热部署加载*Mapper.xml文件,手动刷新*Mapper.xml文件相关推荐

  1. 【Storage】localStorage 或 sessionStorage 首次加载,需要再次手动刷新页面的解决方案

    let val = localStorage.getItem("title");if(val === null){if(location.href.indexOf("#r ...

  2. lombok中的@Data注解与MyBatis的懒加载机制冲突解决

    使用@Data注解与mybatis的懒加载机制实现一对一关系查询时,发现怎么配置都无效,就是一下都查出来了,根本没有懒加载 1.application.yml配置文件配置如下: # mybatis 配 ...

  3. mybatis 的懒加载原理

    断断续续的阅读 mybatis 的源码有好几个月了,想把自己了解到的一些东西与大家分享.今天给大家分享一下 mybatis 的懒加载原理. mybatis 的懒加载过程挺复杂的,涉及到的东西有很多,包 ...

  4. free mybatis 不生效_关于 Mybatis 设置懒加载无效的问题

    看了 mybatis 的教程,讲到关于mybatis 的懒加载的设置: 只需要在 mybatis 的配置文件中设置两个属性就可以了: 但是经过测试之后发现是无效的,经过一番折腾,发现是因为我在测试的时 ...

  5. TOMCAT/JS/CSS/JavaWeb/浏览器老是加载缓存/谷歌浏览器/微软浏览器/刷新键都按烂了/无法加载样式解决办法之一

    禁用浏览器使用缓存. 按F12右键左上角的刷新键"清空缓存并硬性加载". CTRL+F5强制刷新 样式引用更改写法加上时间 等等方法还不行的话 请留意过滤器 如果过滤器有类似这种设 ...

  6. html 下拉滚动加载,原生js滚动到底部加载数据和下拉刷新 Scrollload

    初衷 如今移动端站点越来越多,滚动到底部加载数据和下拉刷新的需求非常的常见,即使现在很多pc站点也会有这样的需求,比如百度首页就有.虽然简单的完成这么一个功能非常方便,但是滚动往往会成为性能的瓶颈,处 ...

  7. 原生js滚动到底部加载数据和下拉刷新 Scrollload

    原文地址 https://github.com/fa-ge/Scrollload/blob/master/README.md 初衷 如今移动端站点越来越多,滚动到底部加载数据和下拉刷新的需求非常的常见 ...

  8. 百度云虚拟主机中的网站不能加载静态js、css和images等文件的解决方案

    百度云虚拟主机下配置个人网站不能加载静态js.css和images等文件时,需要在webroot(网站根目录)下创建bcloud_nginx_user.conf,在这个文件里面设置加载静态文件资源. ...

  9. Android使用RecyclerView实现上拉加载更多,下拉刷新,分组显示

    项目地址:点击打开链接(https://github.com/MrGaoGang/luckly_recyclerview) 使用RecyclerView封装headerview,footerView, ...

最新文章

  1. Homebrew正式支持苹果M1,程序员换新Mac又多了一条理由
  2. DELL optiplex 解决改回 AHCI蓝屏问题
  3. 在PHP里使用 ImageMagick 生成 base64 图片
  4. 8.11zju集训日记
  5. MySQL里面json_MySQL中的JSON
  6. UVa 489 Hangman Judge
  7. SAP UI5函数节流(Throttle)的一个最简单的例子
  8. 数学建模常用算法汇总及python,MATLAB实现(七) —— sklearn和SPSS实现主成分分析
  9. 高斯烟羽模型matlab程序,高斯烟羽模型的改进及在危化品泄漏事故模拟中的应用...
  10. 庆祝下:iOS 开发者企业级计划(299美元/年帐户+邓白氏码免费) 和 Windows Phone公司应用(公司帐户99美元+Symantec企业证书299美元/年))顺利发布成功...
  11. window中的DLL和linux中的os文件是什么东西
  12. 通达OAV12报表中心
  13. python批量图像处理_python图像处理(4)之图像批量处理
  14. [题单]多校补题 2017-2012
  15. 控制系统仿真与CAD-薛定宇-第四章matlab学习笔记
  16. 九龙证券|游戏板块或继续迎来业绩估值“戴维斯双击”
  17. .php文件是病毒吗,php病毒
  18. Elasticsearch Date类型,时间存储相关说明
  19. 情感计算在ugc应用进展
  20. petrel软件中的等值线导出然后加入Geomap4.0中成图/用python处理petrel导出的等值线以便于加入Geomap4.0中

热门文章

  1. cf1491C. Pekora and Trampoline
  2. 「LibreOJ Round #11」Misaka Network 与测试 (网络流跑二分图匹配)
  3. YBTOJ洛谷P4298:祭祀(二分图匹配)
  4. 剪纸游戏(博弈论)(SG函数)
  5. Loj#2460-「POI2010」桥Bridges【网络流,欧拉回路】
  6. P4827-[国家集训队]Crash 的文明世界【树形dp,换根法,斯特林数】
  7. P3807-[模板]卢卡斯定理
  8. 欢乐纪中某B组赛【2018.12.22】
  9. SPOJ687 Repeats(重复次数最多的连续子串)
  10. 各种有用的东西留言板