mybatis 第一个demo,并记一次解决问题:Mapped Statements collection does not contain value for
这个问题是我这边博文的最关键的地方,因为这个问题,浪费了几个小时的时间,搜索了天知道多少篇说这个问题的文章,他们提到的解决方案,包括以下:
1.没有注册,就是没有添加下面的mappers的内容
2.namespace 那里要写对,注册的内容和命名空间的值要一致
整个博文的总结: 对一个mapper的xml文件,要是想引用一个方法,有两个途径:
一、参数直接传那个方法的名字,即定义的id值,上图中1的部分(当然,可能前提是添加了上文提到的build部分的代码才可以!)
二、参数传 namespace+id的值,即上图中1和2的拼接,结果为mapper.UserMapper.xml.getUser
测试结果,上文已经有了!
—————————————————————————————————————————————————————
第一部分:第一个项目
环境:
os:windows 7
ide:idea 2019.1.1
jre:1.8.0
一路OK下去。
然后右键点击项目,
设置maven管理
添加依赖,并同步:
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.8</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
准备工作到此完成,现在开始搞代码逻辑。
项目结构如下所示:
分别代码如下所示:
package bean; public class User { private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package controller; import bean.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class main { public static void main(String[] args) { String resource = "mybatis-config.xml"; InputStream inputStream; try { inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); User user = session.selectOne("mapper.UserMapper.getUser",1); System.out.println("用户id:"+user.getId()+"\t用户名称:"+user.getName()); } catch (IOException e) { e.printStackTrace(); } } }
UserMapper.xml:
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mapper.UserMapper.xml"> <select id="getUser" parameterType="int" resultType="bean.User"> select * from users where id = #{id} </select> </mapper>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="database.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>
database.properties:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/db_name username=xxxxx password=xxxxx
--------------------------------------------------------------------------------------------------------
经过上面的步骤,似乎一切都OK了,知道你一跑起来,发现:
D:\java\bin\java.exe "-javaagent:D:\IDE\IntelliJ IDEA 2019.1.1\lib\idea_rt.jar=53832:D:\IDE\IntelliJ IDEA 2019.1.1\bin" -Dfile.encoding=UTF-8 -classpath D:\java\lib\ant-javafx.jar;D:\java\lib\deploy.jar;D:\java\lib\java.jnlp.jar;D:\java\lib\javafx-swt.jar;D:\java\lib\javaws.jar;D:\java\lib\jdk.deploy.jar;D:\java\lib\jdk.javaws.jar;D:\java\lib\jdk.plugin.dom.jar;D:\java\lib\jdk.plugin.jar;D:\java\lib\jrt-fs.jar;D:\java\lib\plugin-legacy.jar;D:\java\lib\plugin.jar;D:\workspace\server\mybatisDemo\target\classes;D:\workspace\server\mybatisDemo\lib\spring-aspects-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-aop-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-beans-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-context-support-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-context-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-core-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-instrument-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-instrument-tomcat-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-expression-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-jms-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-messaging-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-jdbc-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-orm-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-oxm-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-test-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-tx-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\commons-logging-1.2.jar;D:\workspace\server\mybatisDemo\lib\aopalliance-1.0.jar;C:\Users\Andrew\.m2\repository\mysql\mysql-connector-java\5.1.8\mysql-connector-java-5.1.8.jar;C:\Users\Andrew\.m2\repository\org\mybatis\mybatis\3.5.1\mybatis-3.5.1.jar controller.main Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in mapper/UserMapper.xml ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource mapper/UserMapper.xml 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 controller.main.main(main.java:21) Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource mapper/UserMapper.xml at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78) ... 2 more Caused by: java.io.IOException: Could not find resource mapper/UserMapper.xml at org.apache.ibatis.io.Resources.getResourceAsStream(Resources.java:114) at org.apache.ibatis.io.Resources.getResourceAsStream(Resources.java:100) at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:371) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119) ... 4 more Process finished with exit code 1
这种坑爹的问题,显然我们配置了对应的mapper/UserMapper.xml,仍旧找不到,只有一个问题,就是配置有问题,愚蠢的程序并不知道那个文件在哪里,需要被包括进来。
解决办法就是:在pom.xml文件中添加如下代码:
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>mybatis-config.xml</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>/src/main/resources</directory> </resource> </resources> </build>
相信稍微有点悟性的少年已经明白为什么要这么做:为了让程序在整理打包的时候,把配置的xml文件包括进去
于是,整个的pom.xml就成了如下的样子:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>mybatis-config.xml</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>/src/main/resources</directory> </resource> </resources> </build> <groupId>mybatisId</groupId> <artifactId>mybatisDemo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.8</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
-------------------------------------------------------------------------------------------------
等你做完上面这些步骤之后,兴冲冲的一跑,仍旧会头痛啊头痛,难受啊难受~~~~~!
D:\java\bin\java.exe "-javaagent:D:\IDE\IntelliJ IDEA 2019.1.1\lib\idea_rt.jar=53890:D:\IDE\IntelliJ IDEA 2019.1.1\bin" -Dfile.encoding=UTF-8 -classpath D:\java\lib\ant-javafx.jar;D:\java\lib\deploy.jar;D:\java\lib\java.jnlp.jar;D:\java\lib\javafx-swt.jar;D:\java\lib\javaws.jar;D:\java\lib\jdk.deploy.jar;D:\java\lib\jdk.javaws.jar;D:\java\lib\jdk.plugin.dom.jar;D:\java\lib\jdk.plugin.jar;D:\java\lib\jrt-fs.jar;D:\java\lib\plugin-legacy.jar;D:\java\lib\plugin.jar;D:\workspace\server\mybatisDemo\target\classes;D:\workspace\server\mybatisDemo\lib\spring-aspects-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-aop-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-beans-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-context-support-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-context-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-core-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-instrument-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-instrument-tomcat-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-expression-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-jms-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-messaging-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-jdbc-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-orm-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-oxm-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-test-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\spring-tx-4.3.18.RELEASE.jar;D:\workspace\server\mybatisDemo\lib\commons-logging-1.2.jar;D:\workspace\server\mybatisDemo\lib\aopalliance-1.0.jar;C:\Users\Andrew\.m2\repository\mysql\mysql-connector-java\5.1.8\mysql-connector-java-5.1.8.jar;C:\Users\Andrew\.m2\repository\org\mybatis\mybatis\3.5.1\mybatis-3.5.1.jar controller.main Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.UserMapper.getUser ### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.UserMapper.getUser at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76) at controller.main.main(main.java:23) Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.UserMapper.getUser at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:946) at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:739) at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:732) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:146) ... 3 more Process finished with exit code 1
这个问题是我这边博文的最关键的地方,因为这个问题,浪费了几个小时的时间,搜索了天知道多少篇说这个问题的文章,他们提到的解决方案,包括以下:
1.没有注册,就是没有添加下面的mappers的内容
2.namespace 那里要写对,注册的内容和命名空间的值要一致
···
还有不少,倒是记不清楚了,但是显然我这个工程是没有他们说的这个问题的。
在这个过程中,我近乎绝望地搜索了近3个小时,最后迫不得已,都特么靠不住,只有靠自己了!
接下来是解决问题的过程,与大家分享:
第一步:点击所有出错的语句,进行出错追踪,找到个坑爹的玩意儿到底哪里出了问题。
(其实不用想,肯定是找不到调用的方法,但是为什么找不到,这个才是需要解决的问题!)
然后就会出现对应的代码逻辑:
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76)对应的代码:
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)对应的代码:
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149) 对应的代码:
到了这里,就已经开始抛异常了,说明是第二幅图那里的代码出了问题!
然后第二幅图那里的代码又直接调用了另一个同名不同参的方法,如下图:
如果有人想重现这个步骤,那么像我一样在那一行的代码左边打上debug小红点,一步一步跑起来就行,接下来是逐步分析的过程,debug的进入是小红点这里。
第二步 debug操作
下面正式开始:
跑到第一个出错点 (如果图太大,看不清楚,可以右键在新窗口中打开,方法可以看清晰的图像)
显然并没有什么问题,于是点击上图红圈圈里,往下一个断点运行,下一个断点如下图所示
似乎也没有啥问题,因为毫无变化,除了传进来的两个参数,没有其余变化,继续,然而马上跑到抛异常的这里了显然是在这个过程中,出现的问题。
于是我们需要在没抛异常和抛异常之间的代码,翻得更精确一些,最好一步一步都打上断点,这样才能看到具体的出错过程,下面需要补充一些断点
通过观察出错的代码,上面的横线那里还没出错,因为上面的方法跳转到了下面那个方法里面,在下面方法里面出错了,出错的逻辑,必然在圈圈1,和圈圈2那两行代码里面,不然不可能这样跑出异常,于是把那两个方法都打上断点标记一下。
观察一下那个方法名字和代码逻辑,显然是搞了个字符串用来从配置xml文件里面找到对应的sql语句配置,还是先进入到上面的方法,再添上一个参数后跳到下面那个方法里面
由于get方法,query方法,点进去都是接口,于是没得找了,总不能让我去改框架的代码吧!
只能如此了,那么再来一边debug!
一直跑到那个get的方法那里,如图所示:
那么很清楚的是,红线部分看到我们想要拿的那个变量里面,有两个元素!而我们又毛都没拿到,打开瞧瞧里面到底是个啥玩意儿!!!
显然,这个里面的变量有两个,一个是getUser,另一个是mapper.UserMapper.xml.getUser
就是没有我们在上面提出要找的那个叫做 mapper.UserMapper.getUser 的变量!!
那么我们缓一下调取方法的参数,改成这里面的随意一个,是不是就可以了呢 ?
试试看!
成功了! 这样是可行的!
再来试试另一个变量
又成功了!也是可以的!
那么问题来了,为什么呢?
首先,我特么为什么要写跟namespace里面一样的名字呢?
因为我以前没有搞过这个玩意儿,惭愧,我特么全是抄的别人的demo,
本来是想着好歹跑通第一个程序先,但是我不知道为什么,别人的代码能跑通,我就怎么也跑不通,忧伤加惆怅了很久!
找也找不到解决办法,于是就迫不得已自己干了,于是有了这篇博文!
再次,对于这个问题的结论是啥呢?
对一个mapper的xml文件,要是想引用一个方法,有两个途径:
一、参数直接传那个方法的名字,即定义的id值,上图中1的部分(当然,可能前提是添加了上文提到的build部分的代码才可以!)
二、参数传 namespace+id的值,即上图中1和2的拼接,结果为mapper.UserMapper.xml.getUser
测试结果,上文已经有了!
——————————————————————————————————————————————————————
写在最后,
最为一个小菜鸡,我时常靠着很多大佬的博文解决了海量问题,这些博文都实实在在地提升了我的工作能力,知识水平,更甚至提升了整个程序员群体的工作效率和知识储备,是几乎程序员群体以另一种形式推动着行业的发展。
毕竟,再牛逼的人,解决哪怕再小的问题,都是需要时间的!
这些海量的博文,将许许多多前人工作过的成果以及思考过程,涉及到的知识内容,直接分享了出来,节省了巨大的时间!
这篇博文,说到底就是一个入门级debug过程,
但是我在搜到了天知道多少博文,千篇一律,不仅仅不节省时间,反而浪费了时间,其中以csdn的博文特别多,感觉这是一个相当不好的现象,简直是行业倒退,感觉非常不好。
由于本人自己并没有输出多少高质量的博文,着实惭愧!
鉴于自己写了上面的一段似乎很正直的话,而这样的博文也有益于自己,有益于行业,
本菜鸡以后会多多反思,多多总结,为整个行业的解决方案和节省时间大业,添砖加瓦!
争取以后多多输出高质量的博文
共勉!