MyBatis 核心配置
MyBatis 的核心组成
MyBatis 项目通常包含以下几部分:
- 核心配置文件:配置运行环境、数据源、事务管理器和 Mapper。
- Mapper 接口:声明数据库操作方法。
- Mapper XML:编写 SQL,并建立方法、参数和返回结果之间的映射。
SqlSessionFactory:根据配置创建SqlSession。SqlSession:执行 SQL、获取 Mapper 代理并管理事务。
核心配置文件
核心配置文件通常命名为 mybatis-config.xml。文件名可以自定义,但读取配置时必须使用实际文件名。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/book_shop"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapping/BookMapper.xml"/>
</mappers>
</configuration>environments 可以配置多个运行环境,default 的值必须与某个 environment 的 id 一致。上例选择的是 mysql 环境。
MyBatis 不仅会读取核心配置文件本身,还会根据其中的配置加载外部属性文件、Mapper XML 等资源。例如,<mapper resource="..."/> 表示从类路径加载指定的映射文件,并不是把映射文件内容直接写进核心配置文件。
使用外部属性文件
数据库连接信息通常放在 db.properties 中,避免直接写在 XML 里。
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/book_shop
jdbc.username=root
jdbc.password=1234
在核心配置文件中引入并使用这些属性:
<configuration>
<properties resource="db.properties"/>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<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>
</configuration>Mapper 接口
Mapper 接口用于声明数据库操作。MyBatis 会在运行时为接口创建代理对象,因此通常不需要手写实现类。
public interface BookMapper {
List<TbBook> queryAllBook();
TbBook queryById(Integer id);
int insertBook(TbBook book);
}
方法名、参数类型和返回类型应与 Mapper XML 中对应语句的配置保持一致。
Mapper XML
Mapper XML 负责定义 SQL 和结果映射。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.oracle.dao.BookMapper">
<select id="queryAllBook" resultType="com.oracle.entity.TbBook">
SELECT *
FROM tb_book
</select>
<select id="queryById"
parameterType="java.lang.Integer"
resultType="com.oracle.entity.TbBook">
SELECT *
FROM tb_book
WHERE id = #{id}
</select>
<insert id="insertBook" parameterType="com.oracle.entity.TbBook">
INSERT INTO tb_book(book_name, author, price)
VALUES (#{bookName}, #{author}, #{price})
</insert>
</mapper>namespace 与 id
namespace 应填写 Mapper 接口的全限定类名,id 应与接口方法名一致。这样调用 BookMapper.queryAllBook() 时,MyBatis 才能定位到对应的 SQL 语句。
参数占位符
#{} 会使用预编译参数,能够正确处理类型并降低 SQL 注入风险。普通业务参数应优先使用 #{}。
${} 是字符串直接拼接,通常只用于无法使用参数占位符的位置,例如经过严格白名单校验的排序字段。不要直接把用户输入放入 ${}。
MyBatis 核心 API
创建 SqlSessionFactory
SqlSessionFactoryBuilder 根据配置创建 SqlSessionFactory。工厂对象创建成本较高,应用中通常只创建一个。
public final class MyBatisUtil {
private static final SqlSessionFactory SQL_SESSION_FACTORY;
static {
try (InputStream inputStream =
Resources.getResourceAsStream("mybatis-config.xml")) {
SQL_SESSION_FACTORY =
new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
private MyBatisUtil() {
}
public static SqlSession openSession() {
return SQL_SESSION_FACTORY.openSession();
}
}使用 SqlSession
SqlSession 不是线程安全对象,应在一次业务操作中创建并及时关闭。执行写操作后,需要提交事务;出现异常时应回滚。
public class BookService {
public List<TbBook> queryAllBook() {
try (SqlSession sqlSession = MyBatisUtil.openSession()) {
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
return mapper.queryAllBook();
}
}
public int insertBook(TbBook book) {
try (SqlSession sqlSession = MyBatisUtil.openSession()) {
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
try {
int rows = mapper.insertBook(book);
sqlSession.commit();
return rows;
} catch (RuntimeException e) {
sqlSession.rollback();
throw e;
}
}
}
}也可以使用 openSession(true) 开启自动提交,但在需要多个 SQL 保持原子性的业务中,应使用手动提交。
结果映射
自动映射
当查询结果的列名与 Java 属性名一致时,可以直接使用 resultType。
<select id="queryById" resultType="com.oracle.entity.TbBook">
SELECT id, book_name AS bookName, author, price
FROM tb_book
WHERE id = #{id}
</select>
如果启用了下划线转驼峰配置,book_name 可以自动映射到 bookName。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
手动映射
当数据库列名与 Java 属性名差异较大,或需要复杂映射时,应使用 resultMap。
<mapper namespace="com.oracle.dao.UserMapper">
<resultMap id="userMapping" type="com.oracle.entity.User">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="realName" column="real_name"/>
<result property="password" column="password"/>
<result property="phone" column="phone"/>
<result property="remain" column="remain"/>
<result property="operator" column="operator"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="queryUserById" resultMap="userMapping">
SELECT *
FROM tb_user
WHERE user_id = #{id}
</select>
</mapper>resultType 和 resultMap 都用于描述返回结果,但同一个查询通常只选择其中一种。简单映射使用 resultType,需要明确指定列与属性对应关系时使用 resultMap。
常见问题
找不到映射语句
出现 Invalid bound statement 时,应依次检查:
- Mapper XML 是否位于正确的资源目录。
- 核心配置是否加载了该 Mapper。
namespace是否为接口的全限定类名。- SQL 标签的
id是否与接口方法名一致。 - Maven 构建是否把 XML 文件复制到了类路径。
查询结果属性为 null
应检查数据库列名、Java 属性名和 resultMap 是否一致;使用驼峰命名时,还要检查 mapUnderscoreToCamelCase 是否开启。
写操作没有生效
默认 SqlSession 不会自动提交。执行新增、修改或删除后,应调用 commit();出现异常时调用 rollback(),最后关闭会话。
喜欢的话,留下你的评论吧~