Mybatis热加载Mapper.xml

开发的时候,写Mybatis Mapper.xml文件的时候,每次修改SQL都需要重启服务,感觉十分麻烦,于是尝试写了一个Mybatis的Mapper.xml热加载。

能在修改Mapper.xml之后重新加载Mybatis,开发的时候可以用一下。

Spring配置:

<bean id="MybatisMapperDynamicLoader" class="com.teststartup.MybatisMapperDynamicLoader" />


Java代码:

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

public class MybatisMapperDynamicLoader implements InitializingBean, ApplicationContextAware {

    private final HashMap<String, String> mappers = new HashMap<String, String>();
    private volatile ConfigurableApplicationContext context = null;
    private volatile Scanner scanner = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = (ConfigurableApplicationContext) applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        try {
            scanner = new Scanner();
            new Timer(true).schedule(new TimerTask() {
                public void run() {
                    try {
                        if (scanner.isChanged()) {
                            System.out.println("load mapper.xml");
                            scanner.reloadXML();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, 10 * 1000, 5 * 1000);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    class Scanner {
        private static final String XML_RESOURCE_PATTERN = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "**/*Sql.xml";
        private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        public Scanner() throws IOException {
            Resource[] resources = findResource();
            if (resources != null) {
                for (Resource resource : resources) {
                    String key = resource.getURI().toString();
                    String value = getMd(resource);
                    mappers.put(key, value);
                }
            }
        }
        public void reloadXML() throws Exception {
            SqlSessionFactory factory = context.getBean(SqlSessionFactory.class);
            Configuration configuration = factory.getConfiguration();
            removeConfig(configuration);
            for (Resource resource : findResource()) {
                try {
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration, resource.toString(), configuration.getSqlFragments());
                    xmlMapperBuilder.parse();
                } finally {
                    ErrorContext.instance().reset();
                }
            }
        }
        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");
        }
        private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
            Field field = classConfig.getDeclaredField(fieldName);
            field.setAccessible(true);
            ((Map) field.get(configuration)).clear();
        }
        private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
            Field field = classConfig.getDeclaredField(fieldName);
            field.setAccessible(true);
            ((Set) field.get(configuration)).clear();
        }
        public boolean isChanged() throws IOException {
            boolean isChanged = false;
            for (Resource resource : findResource()) {
                String key = resource.getURI().toString();
                String value = getMd(resource);
                if (!value.equals(mappers.get(key))) {
                    isChanged = true;
                    mappers.put(key, value);
                }
            }
            return isChanged;
        }
        private Resource[] findResource() throws IOException {
            return resourcePatternResolver.getResources(XML_RESOURCE_PATTERN);
        }
        private String getMd(Resource resource) throws IOException {
            return new StringBuilder().append(resource.contentLength()).append("-").append(resource.lastModified()).toString();
        }
    }
}

 

转载于:https://www.cnblogs.com/relucent/p/4108187.html

<think>好的,我现在需要解决用户在MyBatis中遇到的mapper.xml SQL配置错误的问题。用户提到的是“mybatis mapper.xml sql configuration error solution”,我需要根据提供的引用内容和其他知识来提供解决方案。 首先,根据引用[3]提到的,Configuration类是MyBatis的核心配置类,所有配置最终都会维护在这里。所以,如果mapper.xml有错误,可能会导致Configuration加载失败。可能的错误点包括XML语法错误、SQL语句错误、参数映射问题、未定义的标签或属性,以及配置未正确加载等。 接下来,我需要分步骤思考可能的错误原因和解决方法。第一步,检查XML语法是否正确。比如标签是否正确闭合,特殊符号是否转义。例如,在SQL中使用“<”符号应该替换为“<”,否则会导致解析错误。引用[1]中的示例代码展示了正确的XML结构,用户可以对比自己的mapper.xml是否有类似的结构错误。 第二步,检查SQL语句的正确性。比如字段名、表名是否正确,是否使用了数据库保留字未加引号。如果SQL语句有错误,执行时会抛出异常,这时候需要仔细检查SQL的拼写和逻辑。 第三步,参数映射是否正确。MyBatis中参数需要使用#{param}或${param}来引用,如果参数名与Java对象中的属性名不一致,或者类型不匹配,可能会导致错误。需要确保参数占位符正确,并且对应的JavaBean有相应的getter方法。 第四步,标签和属性的正确使用。比如动态SQL中的<if>、<foreach>等标签是否正确嵌套,属性是否填写正确。比如在<select>标签中是否指定了正确的resultType或resultMap。如果使用了未定义的resultMap,也会导致错误。 第五步,确保mapper.xml文件被正确加载。根据引用[2]中提到的,如果修改了mapper.xml但未重启或热加载未生效,可能导致配置未更新。检查mybatis-config.xml中是否配置了<mappers>,并且路径是否正确。例如,使用类路径资源时应该写成<mapper resource="com/example/mapper/UserMapper.xml"/>。 第六步,查看MyBatis的日志输出。根据引用[4],配置日志实现可以帮助查看实际执行的SQL和错误信息。在配置文件中添加<setting name="logImpl" value="SLF4J"/>,然后通过日志定位具体错误,比如参数绑定问题或SQL语法错误。 第七步,验证是否存在缓存问题。有时候旧的缓存可能导致修改后的SQL未生效,尝试清理项目并重新构建,或者禁用MyBatis的缓存配置,如设置<setting name="cacheEnabled" value="false"/>。 综合以上步骤,用户需要逐一排查XML语法、SQL语句、参数映射、标签使用、配置文件加载、日志查看以及缓存问题。此外,如果用户的热加载配置不正确(如引用[2]所述),可能需要确保热加载机制正确实现,或者在开发时手动重启服务以确保配置更新。 最后,生成相关问题,帮助用户进一步解决其他可能的疑问,比如如何动态生成SQL、配置缓存或处理特殊符号转义等。</think>### MyBatis Mapper.xml SQL配置错误解决方案 #### 1. 检查XML语法正确性 - **标签闭合与嵌套**:确保所有标签(如`<select>`, `<insert>`)正确闭合且无嵌套错误。例如: ```xml <select id="getUser" resultType="User"> SELECT * FROM user WHERE id = #{id} <!-- 正确闭合 --> </select> ``` - **特殊符号转义**:SQL中的`<`、`>`等符号需转义为`<`、`>`。例如: ```xml WHERE age < 30 <!-- 错误写法:WHERE age < 30 --> ``` #### 2. 验证SQL语句逻辑 - **字段与表名匹配**:检查SQL中的字段名、表名是否与数据库一致,尤其是大小写敏感问题。 - **保留字处理**:若使用数据库保留字(如`order`),需用反引号包裹:`` `order` ``。 #### 3. 参数映射与占位符 - **正确使用占位符**:动态参数应使用`#{param}`(预编译)或`${param}`(直接替换)。例如: ```xml SELECT * FROM user WHERE name = #{name} <!-- 正确 --> ``` - **参数类型匹配**:确保Java对象属性与SQL占位符名称一致。若参数是Map,需包含对应的key。 #### 4. 标签与属性配置 - **动态SQL标签**:如`<if>`、`<foreach>`需正确嵌套,例如: ```xml <select id="findUsers" resultType="User"> SELECT * FROM user <where> <if test="name != null">AND name = #{name}</if> </where> </select> ``` - **resultMap引用**:若使用`resultMap`,需在XML中明确定义: ```xml <resultMap id="userResultMap" type="User"> <id property="id" column="user_id"/> </resultMap> ``` #### 5. 配置文件加载检查 - **Mapper路径配置**:在`mybatis-config.xml`中确认mapper文件已正确加载: ```xml <mappers> <mapper resource="com/example/mapper/UserMapper.xml"/> <!-- 类路径资源 --> <!-- 或 --> <mapper class="com.example.mapper.UserMapper"/> <!-- 接口注解方式 --> </mappers> ``` - **热加载问题**:若修改后未生效,参考引用[2]的热加载方案或重启服务[^2]。 #### 6. 启用日志调试 - 在`mybatis-config.xml`中配置日志实现(如SLF4J): ```xml <settings> <setting name="logImpl" value="SLF4J"/> <!-- 引用[4] --> </settings> ``` - 通过日志查看实际执行的SQL及参数,定位错误点(如参数绑定失败或语法错误)。 #### 7. 处理缓存问题 - **清理本地编译缓存**:删除`target`目录并重新构建项目。 - **禁用二级缓存**(临时调试): ```xml <settings> <setting name="cacheEnabled" value="false"/> </settings> ``` #### 示例修正对比 **错误配置**: ```xml <update id="updateUser"> UPDATE user SET name=#{name}, age=<30 WHERE id=#{id} </update> ``` **修正后**: ```xml <update id="updateUser"> UPDATE user SET name=#{name}, age < 30 WHERE id=#{id} </update> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值