前言
在不使用Spring
进行初始化Bean
, 单纯的使用Mybatis
的时候, 遇到xml
读取不到的问题。
准备环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> </dependencies>
|
1 2 3 4 5 6 7 8
| create database test; use test; create table user( id int primary key auto_increment, name varchar(50) ); insert into user(name) values ('A'), ('B'), ('C');
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?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>
<settings> <setting name="logImpl" value="SLF4J"/> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"> </transactionManager> <dataSource type="UNPOOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments>
<mappers> <package name="com.ahao.demo.mapper"/> </mappers> </configuration>
|
1 2 3 4 5 6 7 8 9
| <?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="com.ahao.demo.mapper.UserMapper"> <select id="selectAll" resultType="Map"> select * from user </select> </mapper>
|
1 2 3 4 5
| package com.ahao.demo.mapper; import java.util.*; public interface UserMapper { List<Map<String, String>> selectAll(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package com.ahao.test;
import com.ahao.demo.mapper.UserMapper; 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 org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.Reader; import java.util.List;
public class MyTest { private static final Logger logger = LoggerFactory.getLogger(MyTest.class);
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass public static void init() throws IOException { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); }
@Test public void testSelectAll(){ try(SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); System.out.println(userMapper); List user = userMapper.selectAll(); System.out.println(user); } } }
|
分析
运行过后抛出一个异常, statement
没有找到。
1
| org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ahao.demo.mapper.UserMapper.selectAll
|
通过debug
看到sqlSessionFactory
对象中的Configuration
内有两个属性,mapperRegistry
和mappedStatements
看起来是存储mapper
类和对应的Statements
的两个属性。
mapperRegistry
注册成功了, 但是mappedStatements
为空, 也就是Class
加载成功了, xml
加载失败。
xml
自动扫描配置是包扫描, 那么切换成别的可行吗?
1 2 3 4 5 6 7 8
| <mappers> <package name="com.ahao.demo.mapper"/> <mapper resource="UserMapper.xml"/> <mapper class="com.ahao.demo.mapper.UserMapper"/> </mappers>
|
可以看到只有直接指定xml
才能加载成功。
那就是通过Class
自动去寻找对应xml
的时候发生了异常。
翻阅了官方文档, 并没有相关资料。
解决方案
然后检查target
文件夹的时候, 发现UserMapper.xml
和UserMapper.class
没有在同一个文件夹内, 于是将target
下的UserMapper.xml
拖到UserMapper.class
同级目录
。调试发现mappedStatements
有数据。成功了, 推测应该是通过包名转文件路径进行扫描的。
经过测试, 有两种解决方案
- 手动移动
target
文件夹内的mapper.xml
到对应的mapper.class
相同文件夹/WEB-INF/class/com/ahao/demo/mapper
下。
- 将
mapper.xml
放在resource
文件夹内, 对应的文件目录结构/resource/com/ahao/demo/mapper
下。
总结
Mybatis
太坑, 没有个file not found
提示。在IDEA
下, 就算一开始将mapper.xml
文件放在src/java
文件夹下, 编译后也不会将xml
放到target
的相同目录下。
不过有Spring
就不用担心了, Spring
可以指定扫描xml
文件位置。实际开发一般都是和Spring
整合的吧。