mybatis在mapper.xml使用$符号结合IDEA调试难发现的坑

问题

现象: 在测试$和#区别时, mapper.xml使用${username}, 发现始终都被赋值root(即连接用户名)
原因: 在xml配置文件中, ${xxx}占位符, 会被已经存在的键值对优先解析, 如jdbc.properties
解决: Xxxmapper.xml中使用${xxx}时, 避免和其他键值对重名

UserMapper.xml配置

<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
   INSERT INTO user(username, password) VALUES(${
   username}, #{
   password})
</insert>

开启剖析之路

类比似先查看mybatis-config.xml配置的${driver}, ${url}, ${username}, ${password}如何被解析?
查看源码:

// 输入流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// sqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

查看build方法, 一层层点进去, 进到下面这个build, 核心方法是parser.parse方法

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
   
  try {
   
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    
    // 核心在于parser.parse()
    return build(parser.parse());
  } catch (Exception e) {
   
    throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  } finally {
   
    ErrorContext.instance().reset();
    try {
   
      inputStream.close();
    } catch (IOException e) {
   
      // Intentionally ignore. Prefer previous error.
    }
  }
}

查看parser.parse方法

public Configuration parse() {
   
  if (parsed) {
   
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  
  // 核心, 解析configuration配置信息
  parseConfiguration(parser.evalNode("/configuration"));
  return configuration;
}

查看parseConfiguration方法, 关注三个方法
propertiesElement(root.evalNode(“properties”));
environmentsElement(root.evalNode(“environments”));
mapperElement(root.evalNode(“mappers”));

private void parseConfiguration(XNode root) {
   
  try {
   
    // properties标签解析, 把properties文件里面的键值对存到variables
    propertiesElement(root.evalNode("properties"));
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    loadCustomVfs(settings);
    loadCustomLogImpl(settings);
    typeAliasesElement(root.evalNode("typeAliases"));
    pluginElement(root.evalNode("plugins"));
    objectFactoryElement(root.evalNode("objectFactory"));
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
    settingsElement(settings);
    
    // 解析environments, 这里面带有${driver}, ${url}, ${username}, ${password}
    environmentsElement(root.evalNode("environments"));
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    typeHandlerElement(root.evalNode("typeHandlers"));

    // 解析mappers标签
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
   
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}

查看environmentsElement方法

private void environmentsElement(XNode context) throws Exception {
   
  if (context != null) {
   
    if (environment == null) {
   
      environment = context.getStringAttribute("default");
    }
    for (XNode child : context.getChildren(
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值