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

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

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

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

结果是:

Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in com/xh/mybatisLearn/dao/UserMapper.java (best guess)
### 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
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
at com.xh.mybatisLearn.Test.getSqlSessionFactory(Test.java:29)
at com.xh.mybatisLearn.Test.main(Test.java:34)

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

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

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

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

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

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

异常是由:Configuration.class抛出

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

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

value:MappedStatement对象

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

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

Configuration有这个属性:

protected final Map<String, MappedStatement> mappedStatements;

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

debug关键步骤:

XMLConfigBuilder.class解析节点

    private void mapperElement(XNode parent) throws Exception {
if(parent != null) {
Iterator i$ = parent.getChildren().iterator(); while(true) {
while(i$.hasNext()) {
XNode child = (XNode)i$.next();
String resource;
if("package".equals(child.getName())) {
resource = child.getStringAttribute("name");
this.configuration.addMappers(resource);
} else {
resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
XMLMapperBuilder mapperParser;
InputStream mapperInterface1;
if(resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
mapperInterface1 = Resources.getResourceAsStream(resource);
mapperParser = new XMLMapperBuilder(mapperInterface1, this.configuration, resource, this.configuration.getSqlFragments());
mapperParser.parse();<---------------------
} else if(resource == null && url != null && mapperClass == null) {

MapperBuilderAssistant.class:

    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) {
if(this.unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
} else {
id = this.applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
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);
ParameterMap statementParameterMap = this.getStatementParameterMap(parameterMap, parameterType, id);
if(statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
} MappedStatement statement = statementBuilder.build();
this.configuration.addMappedStatement(statement);<---------------------
return statement;
}
}

MapperRegistry.class:

    public <T> void addMapper(Class<T> type) {
if(type.isInterface()) {
if(this.hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
} boolean loadCompleted = false; try {
this.knownMappers.put(type, new MapperProxyFactory(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();<---------------------
loadCompleted = true;

MapperAnnotationBuilder.class:

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);
 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. Linux系统下DNS主从配置详解

    一.DNS概述DNS(Domain Name System),即域名系统.因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串. ...

  2. chrome浏览器安装不上的惨痛经历

    项目在赶进度的时候,手贱把chrome的一些文件删除了,整个浏览器都没法打开 决定重装下,但是连卸载的功能都打不开了 上网重新下载了个安装包,发现安装包都打不来 很绝望,查了很多资料 很多人说要删除注 ...

  3. Zabbix Server 自带模板监控有密码MySQL数据库

    Zabbix Server 自带模板监控有密码MySQL数据库 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.Zabbix-agent端的配置 1>.为数据库设置密码 ...

  4. spring XML配置参数替代properties文件

    xml中配置BEAN与参数 <bean id="beanXXX" class="com.benXXXX" init-method="initia ...

  5. Java Web之JSP

    什么是JSP? JSP就是一个可以写Java代码的HTML页面 JSP是什么? JSP是Servlet,JSP的本质就是Servlet Tomcat的web.xml文件下有这样几段代码: 看到下面的通 ...

  6. eclipse没有server选项

    摘录自:https://www.cnblogs.com/xiaoxiaoweng/p/7298183.html 问题描述:eclipse没有server选项 解决问题:找到Help->Insta ...

  7. base64转换成图片

    前端代码JS: 前端图片为canvsa绘图转base64格式 function putTextInfo() { var canvasImg = painting.canvas.toDataURL('i ...

  8. TIMESTAMP使用遇到得麻烦

    mysql按日期查询报空,怎么查看日志发现是14:36:01.709(Timestamp), 参数出了问题 2018-04-17 14:36:16,887 [http-nio-8080-exec-5] ...

  9. 使用JAVA数组实现顺序表

    1,引入了JAVA泛型类,因此定义了一个Object[] 类型的数组,从而可以保存各种不同类型的对象. 2,默认构造方法创建了一个默认大小为16的Object数组:带参数的构造方法创建一个指定长度的O ...

  10. 苹果手机上点击WEUI日期控件不容易点中

    主要问题是WEUI cells有Padding,而苹果手机一般屏幕较小,容易点不中导致的 <div class='weui_cell' style="padding-bottom:0p ...