mybatis动态更新xml文件后热部署,不重启应用的方法

mybatis应用程序,由于是半自动化的sql, 有大量的sql是在xml文件中配置的,而在开发程序的过程中,通常需要边写sql变调试应用。但在默认情况下,xml文件里配置的sql语句是被放入到缓存中去了,每次更改有sql语句的xml文件,需要重新启动应用,这样工作效率很低,于是很希望有一个动态加载xml文件的功能,自动加载新的sql语句,并重新写入到缓存中,在网上参考了很多资料,最终弄了一个简单的东西出来,直接写成了spring mvc的controller。代码如下: 
 

package com.yihaomen.controller;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Scope("prototype")
@Controller
@RequestMapping("/sql")
public class SQLSessionCacheController {private Log log  = LogFactory.getLog(SQLSessionCacheController.class);@Autowiredprivate SqlSessionFactory sqlSessionFactory;private Resource[] mapperLocations;private String packageSearchPath = "classpath*:**/mappers/*.xml";private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// 记录文件是否变化@RequestMapping("/refresh")@ResponseBodypublic String refreshMapper() {try {Configuration configuration = this.sqlSessionFactory.getConfiguration();// step.1 扫描文件try {this.scanMapperXml();} catch (IOException e) {log.error("packageSearchPath扫描包路径配置错误");return "packageSearchPath扫描包路径配置错误";}System.out.println("==============刷新前mapper中的内容===============");for (String name : configuration.getMappedStatementNames()) {System.out.println(name);}// step.2 判断是否有文件发生了变化if (this.isChanged()) {// step.2.1 清理this.removeConfig(configuration);// step.2.2 重新加载for (Resource configLocation : mapperLocations) {try {XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments());xmlMapperBuilder.parse();log.info("mapper文件[" + configLocation.getFilename() + "]缓存加载成功");} catch (IOException e) {log.error("mapper文件[" + configLocation.getFilename() + "]不存在或内容格式不对");continue;}}}System.out.println("==============刷新后mapper中的内容===============");for (String name : configuration.getMappedStatementNames()) {System.out.println(name);}return "刷新mybatis xml配置语句成功";} catch (Exception e) {e.printStackTrace();return "刷新mybatis xml配置语句失败";}}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;for (Resource resource : mapperLocations) {String resourceName = resource.getFilename();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 || modifyFlag) {fileMapping.put(resourceName, Long.valueOf(lastFrame));// 文件内容帧值flag = true;}}return flag;}
}



注意事项: 
在我的应用中,mybatis配置文件放在这里的:classpath*:**/mappers/*.xml, 因此我定义死了,需要修改成自己的路径. 

测试方法: 
可以通过controller提供的地址,直接在浏览器上输入url访问, 比如: http://localhost:8080/sql/refresh , 当然,你还可以通过js用ajax方式调用,都是可以的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/386773.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode 反转字符串 II python解法

题干&#xff1a; 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起&#xff0c;每计数至 2k 个字符&#xff0c;就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。 如果剩余字符小于 2k 但大于或等于 k 个&#xff0c;…

下拉插件 (带搜索) Bootstrap-select 从后台获取数据填充到select的 option中 用法详解...

今天收到了客户的需求&#xff0c;要求在新增停车场ID的时候要从数据库查出来对应的停车场名称然后显示在界面上。保存的时候按照停车场ID进行保存。 自己首先把后台的部分写完了&#xff0c;测试了接口数据。成功的拿到了ajax数据。 接下来&#xff0c;自己用了select下拉标签…

pytorch tensorboard基本用法整理

from torch.utils.tensorboard import SummaryWriterif __name__ __main__:aa SummaryWriter(logs) # 创建保存了summarywriter的log目录for i in range(100):aa.add_scalar(y x, i, i) # 后两个参数先y轴后x轴 x轴往往是global step y轴用于输出loss或者其他需要观察的变量…

php 支付宝付款接口测试

详细去这里&#xff1a;https://blog.csdn.net/suprezheng/article/details/84931225 转载于:https://www.cnblogs.com/LF-place/p/10898357.html

spring boot mybatis拦截器

mybaits拦截器 package com.chinamobile.scm.masterdata.interceptor;import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apach…

Linux自有服务(2)-Linux从入门到精通第六天(非原创)

文章大纲 一、设置主机名二、chkconfig三、ntp服务四、防火墙服务五、rpm管理&#xff08;重点&#xff09;六、cron/crontab计划任务&#xff08;重点&#xff09;七、学习资料下载八、参考文章 自有服务&#xff0c;即不需要用户独立去安装的软件的服务&#xff0c;而是当系统…

Spring 事务 以及拦截器的前后关系实验 Mybatis 日志拦截

背景&#xff1a;当一个线程中&#xff0c;如果需要拦截所有当SQL日志&#xff0c;然后统一发送到一个同步器&#xff0c;就可以实现多个数据库实现同步主库&#xff0c;在进行红绿上线&#xff0c;或者灰度部署时候&#xff0c;可以实现生产库与测试库实时同步&#xff0c;从而…

四级翻译常用词汇

ancient 古老的&#xff1b;古代的       achieve 获得 v attract 吸引 v            achievement 成就 n attractive 吸引人的          advanced 先进的 account for 对....负有责任&#xff1b;占比   approach 接近&#xff1b;处理&#…

一般拦截器 serviceImpl部分

一般拦截器 serviceImpl部分 package com.chinamobile.scm.masterdata.interceptor;import com.chinamobile.framework.common.context.InvokeTracer; import com.chinamobile.framework.common.context.RequestContext; import com.chinamobile.framework.utils.CollectionUt…

营销-营销方式:营销方式

ylbtech-营销-营销方式&#xff1a;营销方式营销方式是指营销过程中所有可以使用的方法。包括服务营销、体验营销、知识营销、情感营销、教育营销、差异化营销、直销、网络营销等。要有好的营销方式首先要创造行之有效的营销工具。但这并不意味着要把预算的75%都花在印制宣传资…

以后可能用到的一些OQL

Visual VM对OQL的支持 上面我们学会了如何查看堆内存快照&#xff0c;但是&#xff0c;堆内存快照十分庞大&#xff0c;快照中的类数量也很多。Visual VM提供了对OQL&#xff08;对象查询语言&#xff09;的支持&#xff0c;以便于开发人员在庞大的堆内存数据中&#xff0c;快…

leetcode1041困于环中的机器人

题目如下&#xff0c;一道简单的模拟 在无限的平面上&#xff0c;机器人最初位于 (0, 0) 处&#xff0c;面朝北方。机器人可以接受下列三条指令之一&#xff1a;"G"&#xff1a;直走 1 个单位 "L"&#xff1a;左转 90 度 "R"&#xff1a;右转 90…

一个拆分使用的存储过程例子

set serverout on declare var_tmp varchar2(4000) :; var_element varchar2(4000) :; n_length Number : length(\/); begin values_array : VARCHAR_ARRAY(); -- 初始化数组 for i in (select * from sapsr3.zmdm_mthdr where zmtpre in(6200001…

python的pwntools工具的日常使用

1.安装 操作系统&#xff1a; ubuntu16.04 环境准备&#xff1a; pythonpiplibssl-devlibffi-dev pwntools安装&#xff1a; sudo apt-get install libffi-devsudo apt-get install libssl-devsudo apt-get install pythonsudo apt-get install python-pipsudo pip install pwn…

Kibana可视化管理页面详细使用说明

Kibana可视化管理页面详细使用说明 使用浏览器访问 ip:5601 默认端口&#xff0c;进入首页 Discover&#xff1a;日志管理视图 主要进行搜索和查询 Visualize&#xff1a;统计视图 构建可视化的图表 Dashboard&#xff1a;仪表视图 将构…

OO_BLOG3_规格化设计(JML学习)

目录 JML语言学习笔记理论基础应用工具链情况JMLUnit/JMLUnitNGUNIT3 作业分析作业 3-1 实现两个容器类Path和PathContainer作业 3-2 实现容器类Path和数据结构类Graph作业 3-3 实现容器类Path&#xff0c;地铁系统类RailwaySystem规格撰写的心得与体会最后&#xff0c;衷心感谢…

JAVA获取JVM内存空间和物理内存空间

一、获取JVM内存空间 系统环境&#xff1a;WIN JDK版本&#xff1a;1.8re 直接调用Runtime中相应的方法即可&#xff1a; public long maxMemory() Returns the maximum amount of memory that the Java virtual machine will attempt to use. If there is no inherent lim…

CMU Database Systems - Sorting,Aggregation,Join

Sorting 排序如果可在内存里面排&#xff0c;用经典的排序算法就ok&#xff0c;比如快排 问题在于&#xff0c;数据表中的的数据是很多的&#xff0c;没法一下都放到内存里面进行排序 所以就需要用到&#xff0c;外排&#xff0c;多路并归排序 看下最简单的&#xff0c;2路并归…

springboot线程池的使用和扩展

实战环境 windowns10&#xff1b;jdk1.8&#xff1b;springboot 1.5.9.RELEASE&#xff1b;开发工具&#xff1a;IntelliJ IDEA&#xff1b; 实战源码 本次实战的源码可以在我的GitHub下载&#xff0c;地址&#xff1a;gitgithub.com:zq2599/blog_demos.git&#xff0c;项目主…

统计单词个数

我是抄题解狂魔 /* 1.s.substr(x,len) 在s中取出从x位置开始&#xff0c;长度为len的字符串&#xff0c;并返回string类型的字符串。 2.s.find(a) 在s中查找字符串a,并返回起始下标&#xff08;从0开始&#xff09;&#xff0c;若不存在&#xff0c;返回1844674407370955161&am…