(新手入门篇在主页)
ORM(Object-Relational Mapping)即对象关系映射,是一种将数据库表与程序对象自动映射的技术。MyBatis 作为半自动化的 ORM 框架,允许开发者直接编写 SQL,同时自动处理对象与数据库结果的映射。
组件 | 说明 |
---|---|
SqlSessionFactory |
全局单例,用于创建 SqlSession(类似数据库连接池) |
SqlSession |
线程非安全的会话对象,用于执行 SQL 和获取映射器 |
Executor |
SQL 执行器,包含 Simple、Reuse、Batch 三种模式 |
MapperProxy |
动态代理对象,将接口方法调用转换为 SQL 执行 |
新建项目:
File → New → Project → Maven → 选择 JDK 版本
配置目录结构:
src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ ├── entity # 实体类
│ │ ├── dao # Mapper 接口
│ │ └── utils # 工具类
│ ├── resources
│ │ ├── mybatis-config.xml # 主配置文件
│ │ └── mapper/*.xml # Mapper XML
│ └── webapp
│ └── WEB-INF
└── test
└── java # 测试代码
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.13version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.33version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.36version>
dependency>
dependencies>
创建数据库(Navicat 操作):
CREATE DATABASE mybatis_demo
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;
USE mybatis_demo;
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT
);
配置 mybatis-config.xml:
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
configuration>
package com.example.entity;
public class User {
private Integer id;
private String name;
private Integer age;
// Getter & Setter 省略
}
package com.example.dao;
public interface UserMapper {
// 插入用户
int insert(User user);
// 根据 ID 查询
User selectById(Integer id);
// 更新年龄
int updateAge(@Param("id") Integer id, @Param("age") Integer age);
// 删除用户
int delete(Integer id);
}
<mapper namespace="com.example.dao.UserMapper">
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(name, age)
VALUES(#{name}, #{age})
insert>
<select id="selectById" resultType="User">
SELECT * FROM user WHERE id = #{id}
select>
<update id="updateAge">
UPDATE user SET age = #{age} WHERE id = #{id}
update>
<delete id="delete">
DELETE FROM user WHERE id = #{id}
delete>
mapper>
package com.example.utils;
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 MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException("初始化 MyBatis 失败", e);
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
public class UserMapperTest {
@Test
public void testCRUD() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 插入
User user = new User();
user.setName("张三");
user.setAge(25);
mapper.insert(user);
System.out.println("插入ID: " + user.getId());
// 查询
User dbUser = mapper.selectById(user.getId());
System.out.println("查询结果: " + dbUser);
// 更新
mapper.updateAge(user.getId(), 30);
// 删除
mapper.delete(user.getId());
session.commit();
}
}
}
标签 | 作用 | 示例 |
---|---|---|
|
条件判断 |
|
|
多条件选择(类似 switch-case) | 包含 和
|
|
智能去除多余关键字 | 替代 处理复杂条件 |
|
遍历集合 | 用于 IN 查询 |
<select id="selectByCondition" parameterType="map" resultType="User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
if>
<if test="minAge != null">
AND age >= #{minAge}
if>
<if test="maxAge != null">
AND age <= #{maxAge}
if>
where>
ORDER BY id DESC
select>
<insert id="batchInsert" parameterType="list">
INSERT INTO user(name, age) VALUES
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.age})
foreach>
insert>
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<result property="age" column="user_age"/>
resultMap>
<select id="selectComplex" resultMap="userResultMap">
SELECT
id AS user_id,
name AS user_name,
age AS user_age
FROM user
select>
<resultMap id="userWithOrders" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="orders" ofType="Order">
<id property="orderId" column="order_id"/>
<result property="orderNo" column="order_no"/>
collection>
resultMap>
<select id="selectUserWithOrders" resultMap="userWithOrders">
SELECT
u.*,
o.id AS order_id,
o.no AS order_no
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
select>
try (SqlSession session = sqlSessionFactory.openSession()) {
try {
UserMapper mapper = session.getMapper(UserMapper.class);
// 业务操作
session.commit();
} catch (Exception e) {
session.rollback();
}
}
一级缓存:
二级缓存:
需在 mapper.xml 中启用:
<cache eviction="LRU" flushInterval="60000" size="1024"/>
实体类需实现 Serializable
接口
@WebServlet("/user")
public class UserServlet extends HttpServlet {
private UserMapper userMapper;
@Override
public void init() {
SqlSession session = MyBatisUtil.getSqlSession();
userMapper = session.getMapper(UserMapper.class);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
List<User> users = userMapper.selectAll();
// 将数据传递到 JSP
req.setAttribute("users", users);
req.getRequestDispatcher("/userList.jsp").forward(req, resp);
}
}
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
用户列表
ID
姓名
年龄
${user.id}
${user.name}
${user.age}
现象:Invalid bound statement (not found)
解决:
检查 XML 文件是否在 resources/mapper
目录
确认 mybatis-config.xml 中
路径正确
Maven 添加资源过滤:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.xmlinclude>
includes>
resource>
resources>
build>
解决:
数据库连接 URL 添加参数:
jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8
确保 JSP 页面设置编码:
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>4.4.6version>
dependency>
public class RedisCache implements Cache {
private final String id;
private static JedisPool jedisPool;
public RedisCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.hset(id, key.toString(), SerializeUtil.serialize(value));
}
}
@Override
public Object getObject(Object key) {
try (Jedis jedis = jedisPool.getResource()) {
return SerializeUtil.unserialize(jedis.hget(id, key.toString()));
}
}
}
MyBatis 以配置化与动态代理为核心,通过解耦 SQL 与代码、自动化结果映射及灵活的动态 SQL 标签,将 JDBC 的繁琐操作转化为简洁的接口方法。其分层架构(接口层、核心处理层、基础支持层)结合 XML/注解配置,既保留了原生 SQL 的灵活性,又通过批处理、分页优化与二级缓存机制提升了性能,同时依托插件体系与 Spring 集成实现事务管理和扩展定制,最终在简化开发、保障安全性与维护性之间取得了优雅平衡,成为 Java 持久层的高效解决方案。
通过本文的系统学习,您已掌握 MyBatis 的核心用法与进阶技巧。建议从简单项目入手,逐步实践复杂场景,最终达到精通水平。