接入门的实例,我们知道MyBatis可以使用注解和配置文件实现接口和sql语句的绑定。

那么一个接口方法同时使用注解和xml配置会怎么样。

  1. @Select("select * from user_tb where id=#{id}")
  2. User getOneUser(int id);
  1. <select id="getOneUser" resultType="User">
  2. select * from user_tb where id+1=#{id}
  3. </select>

如果传入id=12,查出来的User.id=12,说明注解覆盖xml配置,查出来的User.id=11,说明xml配置覆盖注解

结果是:

  1. Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException:
  2. ### Error building SqlSession.
  3. ### The error may exist in com/xh/mybatisLearn/dao/UserMapper.java (best guess)
  4. ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.xh.mybatisLearn.dao.UserMapper.getOneUser
  5. at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
  6. at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
  7. at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
  8. at com.xh.mybatisLearn.Test.getSqlSessionFactory(Test.java:29)
  9. at com.xh.mybatisLearn.Test.main(Test.java:34)

竟然抛异常啦,去掉任何一个都是可以的。其实这个可以理解,因为实在没有理由这么干。

我现在想看看到时是哪个方法抛出异常的怎么办?

我的办法是边debug边下断点:

比如第一次在执行A()抛异常,那么就在A处下断点,下次运行到A的时候进入,然后B()抛异常,在B()下断点。。。。

如果经过的方法很多可以去掉之前的一些断点,只保留关键的方法(后期需要分析)

可能有人喜欢边debug边读源码,但我偏好先不读代码,找到抛出异常的源头,回头在根据断点一步步看源码,这样脉络更清晰。

异常是由:Configuration.class抛出

  1. public V put(String key, V value) {
  2. if(this.containsKey(key)) {
  3. throw new IllegalArgumentException(this.name + " already contains value for " + key);
  4. } else {

key:com.xh.mybatisLearn.dao.UserMapper.getOneUser

value:MappedStatement对象

原来是这里保证了每个接口方法只有一个MappedStatement对象。

  1. public void addMappedStatement(MappedStatement ms) {
  2. this.mappedStatements.put(ms.getId(), ms);
  3. }

Configuration有这个属性:

  1. protected final Map<String, MappedStatement> mappedStatements;

++++++++++++++++++++++++++

debug关键步骤:

XMLConfigBuilder.class解析节点

  1. private void mapperElement(XNode parent) throws Exception {
  2. if(parent != null) {
  3. Iterator i$ = parent.getChildren().iterator();
  4.  
  5. while(true) {
  6. while(i$.hasNext()) {
  7. XNode child = (XNode)i$.next();
  8. String resource;
  9. if("package".equals(child.getName())) {
  10. resource = child.getStringAttribute("name");
  11. this.configuration.addMappers(resource);
  12. } else {
  13. resource = child.getStringAttribute("resource");
  14. String url = child.getStringAttribute("url");
  15. String mapperClass = child.getStringAttribute("class");
  16. XMLMapperBuilder mapperParser;
  17. InputStream mapperInterface1;
  18. if(resource != null && url == null && mapperClass == null) {
  19. ErrorContext.instance().resource(resource);
  20. mapperInterface1 = Resources.getResourceAsStream(resource);
  21. mapperParser = new XMLMapperBuilder(mapperInterface1, this.configuration, resource, this.configuration.getSqlFragments());
  22. mapperParser.parse();<---------------------
  23. } else if(resource == null && url != null && mapperClass == null) {

MapperBuilderAssistant.class:

  1. public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class<?> parameterType, String resultMap, Class<?> resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang, String resultSets) {
  2. if(this.unresolvedCacheRef) {
  3. throw new IncompleteElementException("Cache-ref not yet resolved");
  4. } else {
  5. id = this.applyCurrentNamespace(id, false);
  6. boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
  7. org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = (new org.apache.ibatis.mapping.MappedStatement.Builder(this.configuration, id, sqlSource, sqlCommandType)).resource(this.resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(this.getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(((Boolean)this.valueOrDefault(Boolean.valueOf(flushCache), Boolean.valueOf(!isSelect))).booleanValue()).useCache(((Boolean)this.valueOrDefault(Boolean.valueOf(useCache), Boolean.valueOf(isSelect))).booleanValue()).cache(this.currentCache);
  8. ParameterMap statementParameterMap = this.getStatementParameterMap(parameterMap, parameterType, id);
  9. if(statementParameterMap != null) {
  10. statementBuilder.parameterMap(statementParameterMap);
  11. }
  12.  
  13. MappedStatement statement = statementBuilder.build();
  14. this.configuration.addMappedStatement(statement);<---------------------
  15. return statement;
  16. }
  17. }

MapperRegistry.class:

  1. public <T> void addMapper(Class<T> type) {
  2. if(type.isInterface()) {
  3. if(this.hasMapper(type)) {
  4. throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
  5. }
  6.  
  7. boolean loadCompleted = false;
  8.  
  9. try {
  10. this.knownMappers.put(type, new MapperProxyFactory(type));
  11. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
  12. parser.parse();<---------------------
  13. loadCompleted = true;

MapperAnnotationBuilder.class:

  1. this.assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, (String)null, parameterTypeClass, var26, this.getReturnType(method), resultSetType, flushCache, useCache, false, (KeyGenerator)keyGenerator, keyProperty, keyColumn, (String)null, languageDriver, options != null?this.nullOrEmpty(options.resultSets()):null);
  1. this.configuration.addMappedStatement(statement);

最后回到:Configuration.class:

MyBatis-进阶1的更多相关文章

  1. mybatis进阶案例之多表查询

    mybatis进阶案例之多表查询 一.mybatis中表之间的关系 在数据库中,实体型之间的关系主要有如下几种: 1.一对一 如果对于实体集A中的每一个实体,实体集B中至多有一个(也可以没有)实体与之 ...

  2. 《Mybatis进阶》肝了30天专栏文章,整理成册,免费获取!!!

    持续原创输出,点击上方蓝字关注我吧 目录 前言 简介 如何获取? 总结 前言 Mybatis专栏文章写到至今已经有一个月了,从基础到源码详细的介绍了每个知识点,没什么多余的废话,全是工作.面试中常用到 ...

  3. mybatis进阶

    1.mybatis一对一映射 Student--Card <?xml version="1.0" encoding="utf-8" ?> <! ...

  4. mybatis进阶--一对一查询

    所谓的一对一查询,就是说我们在查询一个表的数据的时候,需要关联查询其他表的数据. 需求 首先说一个使用一对一查询的小需求吧:假设我们在查询某一个订单的信息的时候,需要关联查询出创建这个订单对应的用户信 ...

  5. MyBatis进阶(一)运行原理

    初次学习MyBatis,自己花了不少时间,理解一件事物是需要时间的.经过多次反复的理解,你的认知能力就可以得到提升.以下是学习MyBatis的一些理解认识,技术理解上若有不当之处,敬请朋友们提出宝贵意 ...

  6. MyBatis进阶使用——动态SQL

    MyBatis的强大特性之一就是它的动态SQL.如果你有使用JDBC或者其他类似框架的经验,你一定会体会到根据不同条件拼接SQL语句的痛苦.然而利用动态SQL这一特性可以彻底摆脱这一痛苦 MyBati ...

  7. MyBatis进阶(三)

    MyBatis批量新增数据 1. 传统的JDBC批量插入数据 使用for循环 创建连接 获取连接 创建sql语句,交给连接 使用for循环新增数据 提交连接 使用批处理 两者都存在严重的效率问题,代码 ...

  8. MyBatis进阶(二)

    MyBatis之动态SQL 动态SQL之foreach 有时SQL语句where条件是在一个集合或者数组里,需要使用in关键字,这时可以使用foreach动态SQL语句,例如: select * fr ...

  9. MyBatis进阶(一)

    MyBatis参数传递 1. MyBatis单参数传递 单参数传递不做特殊处理,直接取出参数值赋给xml文件,如#{id} 2. MyBatis多参数传递 多参数传递默认使用{arg1, arg0, ...

  10. mybatis进阶--一对多查询

    首先,我们还是先给出一个需求:根据订单id查询订单明细——我们知道,一个订单里面可以有多个订单的明细(需求不明确的同学,请留言或者去淘宝网上的订单处点一下就知道了).这个时候,一个订单,对应多个订单的 ...

随机推荐

  1. oracle出现无法响应新的请求,报ora-12516错误

    oracle的会话数超出了限制,一般都是由于多次connect建立多个连接会话引起.   解决办法: (oracle登录后台,1)sqlplus /nolog  2)conn / as sysdba) ...

  2. 2017-12-18python全栈9期第三天第一节之昨天内容回顾与作业讲解用户三次机会再试试

    #!/user/bin/python# -*- coding:utf-8 -*-username = "zd"password = "123"i = 3whil ...

  3. scrapy基础二

    应对反爬虫机制 ①.禁止cookie :有的网站会通过用户的cookie信息对用户进行识别和分析,此时可以通过禁用本地cookies信息让对方网站无法识别我们的会话信息 settings.py里开启禁 ...

  4. Hadoop记录-HDFS配额Quota

    设置文件数配额 hdfs dfsadmin -setQuota <N> <directory>...<directory> 例如:设置目录下的文件总数为1000个h ...

  5. C#设计模式(9)——代理模式

    1.代理模式介绍 在软件开发中有时会遇到不能直接使用对象的问题,如我们要使用的对象在进程外,甚至在远程的机器上,但是我们要使用这个对象的功能怎么办呢?代理模式就可以用来解决这个问题.举一个生活中的例子 ...

  6. Sqlserver中的索引

    一.什么是索引及索引的优缺点 1.1  索引的基本概念 数据库索引,是数据库管理系统中一个排序的数据结构,用来协助快速查询数据库表中数据. 简单理解索引就是一个排好顺序的目录,设置了索引就意味着进行了 ...

  7. Ubuntu Server 16.04 安装MySQL并设置远程访问

    Ubuntu Server 16.04 安装MySQL 1. 使用root账号 sudo apt-get install mysql-serversudo apt-get install mysql- ...

  8. Eclipse 中报错的阅读顺序

    1 九月 19, 2018 8:49:53 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefin ...

  9. [leetcode-117]填充每个节点的下一个右侧节点指针 II

    (1 AC) 填充每个节点的下一个右侧节点指针 I是完美二叉树.这个是任意二叉树 给定一个二叉树 struct Node { int val; Node *left; Node *right; Nod ...

  10. 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、Git/SVN)

    一. 各类概念和指令介绍 1. NVM (1).  全称:Node Version Manager,是一款针对Nodejs的版本管理工具,由于Node的版本很多,很多时候我要需要依赖多个版本,并且要求 ...