MyBatis
1️⃣ 什么是 MyBatis?——JDBC 的“救世主”!
还记得写 JDBC 时那堆 Class.forName()、Connection、PreparedStatement、ResultSet 吗?
每次都要手动开关连接、拼 SQL、解析结果……简直像在搬砖!🧱
MyBatis 就是来解放你的双手的!
✅ 它是一个优秀的持久层框架,帮你自动处理:
- 数据库连接
- SQL 参数设置
- 结果集映射成 Java 对象(ORM)
👉 你只需要专注写 SQL 和 Java 接口,剩下的交给 MyBatis!
💡 小知识:MyBatis 原名 iBatis,2010 年从 Apache 迁移到 Google Code 后改名。名字 = Internet + abatis(一种鱼),寓意“灵活如鱼”🐟。
2️⃣ Hello MyBatis!入门案例走起 🚀
步骤一:建表 & 准备数据
CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
birthday DATE,
sex VARCHAR(10),
address VARCHAR(100)
);
INSERT INTO user VALUES
(41, '张三丰', '1980-01-01', '男', '武当山'),
(42, '马德华', '1975-05-05', '男', '高老庄');
步骤二:Maven 依赖(pom.xml)
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version> <!– 推荐用新版本 –>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<!– 包含 src/main/java 下的 Mapper XML 文件 –>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!– 包含 src/main/resources 下的所有配置文件 –>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
⚠️ 别忘了 <build> 里加 resources,否则 XML 文件打包会丢失!
步骤三:实体类 User.java
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// getter / setter / toString()
}
步骤四:DAO 接口 UserDao.java
public interface UserDao {
List<User> findAll();
}
步骤五:映射文件 UserDao.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="com.hg.dao.UserDao">
<select id="findAll" resultType="com.hg.pojo.User">
SELECT * FROM user
</select>
</mapper>
🔑 namespace 必须和接口全路径一致!
🔑 id 必须和方法名一致!
🔑 resultType 是返回对象的全类名!
步骤六:核心配置 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>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="1111"/>
</dataSource>
</environment>
</environments>
<!– 加载映射文件 –>
<mappers>
<mapper resource="com/hg/dao/UserDao.xml"/>
</mappers>
</configuration>
步骤七:测试 Test
public class MyBatisTest {
private SqlSession sqlSession;
@Before
public void init() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
}
@Test
public void testFindAll() {
UserDao dao = sqlSession.getMapper(UserDao.class);
List<User> users = dao.findAll();
users.forEach(System.out::println);
}
@After
public void destroy() {
sqlSession.close();
}
}
🎉 成功输出用户信息!恭喜你迈出了第一步!
3️⃣ CRUD 操作大全 —— 增删改查 So Easy!
✅ 查询(单参数)
User findUserById(Integer id);
<select id="findUserById" parameterType="int" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
💡 #{} 是安全的占位符,防 SQL 注入!
✅ 多参数传递(三种方式)
方式1:按位置(不推荐)
User findUserByIdAndName(Integer id, String name);
<!– arg0, arg1… 或 param1, param2… –>
SELECT * FROM user WHERE id = #{arg0} AND username = #{arg1}
方式2:@Param 注解(推荐!)
User findUserByIdAndName(@Param("id") Integer id, @Param("name") String name);
SELECT * FROM user WHERE id = #{id} AND username = #{name}
方式3:封装成对象 or Map
User findByUser(User user);
// 或
User findByMap(Map<String, Object> map);
🔍 模糊查询(小心 SQL 注入!)
List<User> findByName(String name);
<!– 安全写法(推荐) –>
<select id="findByName" parameterType="string" resultType="User">
SELECT * FROM user WHERE username LIKE CONCAT('%', #{name}, '%')
</select>
<!– 危险写法(慎用!) –>
SELECT * FROM user WHERE username LIKE '%${value}%'
❗ ${} 是直接拼接字符串,有注入风险!只在动态表名/列名时使用。
➕ 插入 & 主键回显(重点!🌟)
需求:插入用户后,自动获取数据库生成的自增 ID,并赋值给 Java 对象的 id 字段。
方法一:使用 <selectKey>
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO user(username, birthday, sex, address)
VALUES (#{username}, #{birthday}, #{sex}, #{address})
</insert>
方法二:使用 useGeneratedKeys(更简洁!)
<insert id="insertUser"
parameterType="User"
useGeneratedKeys="true"
keyProperty="id">
INSERT INTO user(username, birthday, sex, address)
VALUES (#{username}, #{birthday}, #{sex}, #{address})
</insert>
✅ 测试时你会发现:user.getId() 有值了!这就是主键回显!
User user = new User();
user.setUsername("刘德华");
user.setAddress("香港");
userDao.insertUser(user);
System.out.println("新用户ID:" + user.getId()); // 输出:68
✏️ 更新 & 删除
<update id="updateUser" parameterType="User">
UPDATE user SET username=#{username}, address=#{address}
WHERE id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
⚠️ 记得 sqlSession.commit()!否则事务不会提交!
4️⃣ 关联查询 —— 一对多、多对多也不怕!
🔗 一对一(Account → User)
public class Account {
private Integer id;
private Integer uid;
private Double money;
private User user; // 关联用户
}
<resultMap id="accountWithUser" type="Account">
<id property="id" column="aid"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<association property="user" javaType="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountWithUser">
SELECT a.id AS aid, a.uid, a.money, u.*
FROM account a
JOIN user u ON a.uid = u.id
</select>
🔗 一对多(User → List)
public class User {
// … 其他字段
private List<Account> accounts;
}
<resultMap id="userWithAccounts" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="accounts" ofType="Account">
<id property="id" column="aid"/>
<result property="money" column="money"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userWithAccounts">
SELECT u.*, a.id AS aid, a.money
FROM user u
LEFT JOIN account a ON u.id = a.uid
</select>
🔗 多对多(Role ↔ User)
通过中间表 user_role(uid, rid) 实现。
<resultMap id="roleWithUsers" type="Role">
<id property="id" column="rid"/>
<result property="roleName" column="role_name"/>
<collection property="users" ofType="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
</collection>
</resultMap>
<select id="findAll" resultMap="roleWithUsers">
SELECT r.id AS rid, r.role_name, u.*
FROM role r
LEFT JOIN user_role ur ON r.id = ur.rid
LEFT JOIN user u ON ur.uid = u.id
</select>
5️⃣ 动态 SQL —— 让 SQL “活”起来!
🧪 if + where(条件查询)
<select id="findByUser" resultType="User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="sex != null">
AND sex = #{sex}
</if>
</where>
</select>
✅ <where> 会自动去掉开头的 AND!
✏️ set(动态更新)
<update id="updateUser">
UPDATE user
<set>
<if test="username != null">username = #{username},</if>
<if test="address != null">address = #{address},</if>
</set>
WHERE id = #{id}
</update>
✅ <set> 自动去掉末尾的逗号!
🔁 foreach(批量操作)
<!– 批量删除 –>
<delete id="deleteByIds">
DELETE FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
<!– 批量插入 –>
<insert id="insertUsers">
INSERT INTO user(username, address) VALUES
<foreach collection="userList" item="user" separator=",">
(#{user.username}, #{user.address})
</foreach>
</insert>
6️⃣ 缓存机制 —— 飞一般的速度!
🥇 一级缓存(SqlSession 级别)
- 默认开启!
- 同一个 SqlSession 中,相同查询只查一次数据库。
- 执行增删改 or commit() or close() 会清空缓存。
🥈 二级缓存(Mapper 级别)
- 多个 SqlSession 共享!
- 需要手动开启:
<!– mybatis-config.xml –>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!– UserDao.xml –>
<mapper namespace="…">
<cache/> <!– 开启二级缓存 –>
…
</mapper>
⚠️ 实体类必须实现 Serializable!
7️⃣ 注解开发(了解即可)
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Integer id);
@Insert("INSERT INTO user(username) VALUES(#{username})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUser(User user);
💬 优点:代码简洁
💬 缺点:SQL 写死在 Java 里,难维护!
👉 复杂项目建议用 XML!
✅ 总结
| 入门 | 配置文件 + Mapper + SqlSession |
| CRUD | #{} 安全,${} 危险 |
| 主键回显 | useGeneratedKeys="true" + keyProperty |
| 关联查询 | <association> / <collection> |
| 动态 SQL | if, where, set, foreach |
| 缓存 | 一级(默认),二级(需配置) |


