1.bug背景
1.1.MyBatis配置文件
<?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="jdbc.properties"/>
<!-- environments:多环境配置的标签 元配置信息default必须存在, 代表使用作为默认加载的环境 -->
<environments default="development">
<!-- environment标签代表具体的某个环境配置信息id必须存在,作为当前环境的唯一标志-->
<environment id="development">
<transactionManager type="JDBC"/>
<!--dataSource表示数据源的配置:=>POOLED代表使用连接池 =>UNPOOLED:代表直连-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="pers.lintao.dao"/>
</mappers>
</configuration>
1.2.映射文件
<?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="pers.lintao.dao.PersonTableDao">
<resultMap type="pers.lintao.entity.PersonTable" id="PersonTableMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="pname" column="pname" jdbcType="VARCHAR"/>
<result property="psex" column="psex" jdbcType="VARCHAR"/>
<result property="idCardId" column="id_card_id" jdbcType="INTEGER"/>
</resultMap>
<!--查询单个-->
<select id="queryById" resultMap="PersonTableMap">
select
id, pname, psex, id_card_id
from person_table
where id = #{id}
</select>
</mapper>
1.3.dao层接口
public interface PersonTableDao {
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
PersonTable queryById(Integer id);
}
1.4.工具类
public class MyBatisUtil {
private static SqlSession sqlSession;
public static SqlSession createSqlSession() throws IOException {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
public static void close(SqlSession sqlSession){
sqlSession.close();
}
}
1.5.单元测试
@Test
public void testQuery() throws Exception {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtil.createSqlSession();
PersonTableDao mapper = sqlSession.getMapper(PersonTableDao.class);
PersonTable personTable = mapper.queryById(1);
System.out.println(personTable);
} catch (IOException e) {
e.printStackTrace();
throw new Exception("创建SqlSession出错异常");
} finally {
if (sqlSession != null){
MyBatisUtil.close(sqlSession);
}
}
}
2.bug详情
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): pers.lintao.dao.PersonTableDao.queryById
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53)
at org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:108)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at org.apache.ibatis.util.MapUtil.computeIfAbsent(MapUtil.java:36)
at org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:95)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
at com.sun.proxy.$Proxy8.queryById(Unknown Source)
at QueryTest.testQuery(QueryTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
3.解决bug
修改前:
<mappers>
<package name="pers.lintao.dao"/>
</mappers>
修改后:
<mappers>
<mapper resource="mappers/PersonTableDao.xml"/>
</mappers>
4.原因总结
<mappers>标签中的子标签只有mapper,package两种;并且同时只能出现一种(The content of element type "mappers" must match "(mapper*,package*)"):
<!-- 1.mapper适用于xml文件和接口配合适用,也可以可以不用配置<mapper class="pers.lintao.dao.PersonTableDao"/>,因为在xml映射件中的namespace的值就是接口的全限定名 -->
<mappers>
<mapper resource="mappers/PersonTableDao.xml"/>
</mappers>
或者(必须接口配置在前)
<mappers>
<mapper class="pers.lintao.dao.PersonTableDao"/>
<mapper resource="mappers/PersonTableDao.xml"/>
</mappers>
<!-- 2.package配置适用于mybatis注解开发 -->
<mappers>
<package name="pers.lintao.dao"/>
</mappers>
5.bug拓展
<!--xml文件在dao层接口之前注册-->
<mappers>
<mapper resource="mappers/PersonTableDao.xml"/>
<mapper class="pers.lintao.dao.PersonTableDao"/>
</mappers>
就会报以下异常:
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.
Cause: org.apache.ibatis.binding.BindingException:
Type interface pers.lintao.dao.PersonTableDao is already known to the MapperRegistry.