mybatis application program, because it is semi-automated sql, a large number of SQL is configurated in XML files, and in the process of developing programs, it is usually necessary to write SQL variable debugging applications. But by default, SQL statements configurated in XML files are put into the cache. Every time an XML file with SQL statements is changed, the application needs to be restarted, which is inefficient. Therefore, it is very desirable to have a function of dynamically loading xml files, automatically loading new SQL statements, and re-writing them into the cache. A lot of information is referred to online, and finally a new one is created. Simple things come out and are written directly as controller of spring mvc. The code is as follows:
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); @Autowired private SqlSessionFactory sqlSessionFactory; private Resource[] mapperLocations; private String packageSearchPath = "classpath*:**/mappers/*.xml"; private HashMap<String, Long> fileMapping = new HashMap<String, Long>();// Does the record file change? @RequestMapping("/refresh") @ResponseBody public String refreshMapper() { try { Configuration configuration = this.sqlSessionFactory.getConfiguration(); // step.1 Scan file try { this.scanMapperXml(); } catch (IOException e) { log.error("packageSearchPath Scanning Packet Path Configuration Error "; return "packageSearchPath Scanning Packet Path Configuration Error. } System.out.println("==============Content in mapper before refresh=========================="; for (String name : configuration.getMappedStatementNames()) { System.out.println(name); } // step.2 Determine if any documents have changed if (this.isChanged()) { // step.2.1 Clear this.removeConfig(configuration); // step.2.2 Reload for (Resource configLocation : mapperLocations) { try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configLocation.getInputStream(), configuration, configLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); log.info("mapper The file ["+configLocation.getFilename()+"] cached successfully "; } catch (IOException e) { log.error("mapper The file ["+configLocation.getFilename()+"] does not exist or the content format is incorrect "; continue; } } } System.out.println("==============The content in mapper after refresh=========================="; for (String name : configuration.getMappedStatementNames()) { System.out.println(name); } return "The mybatis xml configuration statement was successfully refreshed. } catch (Exception e) { e.printStackTrace(); return "Failed to refresh mybatis xml configuration statement. } } public void setPackageSearchPath(String packageSearchPath) { this.packageSearchPath = packageSearchPath; } public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } /** * The path where the xml file is scanned * @throws IOException */ private void scanMapperXml() throws IOException { this.mapperLocations = new PathMatchingResourcePatternResolver().getResources(packageSearchPath); } /** * Empty several important caches in 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(); } /** * Determine whether the document has changed * @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);// This is a new logo // Modify the document: Determine whether the content of the document has changed Long compareFrame = fileMapping.get(resourceName); long lastFrame = resource.contentLength() + resource.lastModified(); boolean modifyFlag = null != compareFrame && compareFrame.longValue() != lastFrame;// This is the modified identifier // Store files when new or modified if(addFlag || modifyFlag) { fileMapping.put(resourceName, Long.valueOf(lastFrame));// File Content Frame Value flag = true; } } return flag; } }
Notes:
In my application, the mybatis configuration file is placed here: classpath*:**/mappers/*.xml, so I've defined it dead and need to modify it to my own path.
Test methods:
You can access it directly by entering url on the browser through the address provided by the controller, such as: http://localhost:8080/sql/refresh Of course, you can also use ajax to call through js, which is all right.