本文将继续深入,讲解如何使用 Mapper 接口方式 完成 插入(Insert)、修改(Update)和删除(Delete) 操作,并强调事务控制的重要性。
一、为什么增删改必须关注事务?
与 SELECT 不同,INSERT / UPDATE / DELETE 是 写操作 ,会修改数据库状态。
MyBatis 默认 不自动提交事务 (即 autoCommit = false),因此:
- ✅ 若操作成功,需手动调用
sqlSession.commit()提交; - ❌ 若未提交,程序结束后更改将被回滚,数据不会真正写入数据库!
💡 这也是我们在
MyBatisUtil.getSqlSession()中传入false的原因 ------ 由开发者显式控制事务。
二、准备工作
1. 实体类(TblClient.java)保持不变
public class TblClient {
private Integer cid;
private String cname;
private String caddress;
private Date cbirthday;
// getter / setter 略
}
2. Mapper 接口新增 CRUD 方法
// com.charles.dao.ClientMapper.java
package com.charles.dao;
import java.util.List;
import com.charles.entity.TblClient;
public interface ClientMapper {
// 查询
List<TblClient> getClientAll();
// 新增
void insertClient(TblClient client);
// 修改
void updateClient(TblClient client);
// 删除
void deleteClientById(Integer cid);
}
🔔 方法命名规范:建议语义清晰,如
insertXxx、updateXxx、deleteXxxByYyy。
三、XML 映射文件配置(ClientMapper.xml)
在原有基础上,新增以下标签:
<!-- 插入新客户 -->
<insert id="insertClient" parameterType="baitang">
INSERT INTO tbl_client (client_name, client_address, client_birthday)
VALUES (#{cname}, #{caddress}, #{cbirthday})
</insert>
<!-- 更新客户信息 -->
<update id="updateClient" parameterType="baitang">
UPDATE tbl_client
SET
client_name = #{cname},
client_address = #{caddress},
client_birthday = #{cbirthday}
WHERE id = #{cid}
</update>
<!-- 根据ID删除客户 -->
<delete id="deleteClientById" parameterType="int">
DELETE FROM tbl_client WHERE id = #{cid}
</delete>
✅ 注意:
parameterType可写全限定类名,也可用别名(如baitang);#{}占位符会自动进行预编译,防止 SQL 注入。
四、单元测试:完整演示增删改
// com.charles.junit.JunitMybaitsCRUD.java
package com.charles.junit;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.charles.dao.ClientMapper;
import com.charles.entity.TblClient;
import com.charles.util.MyBatisUtil;
public class JunitMybaitsCRUD {
@Test
public void testCRUD() {
SqlSession session = MyBatisUtil.getSqlSession();
ClientMapper mapper = session.getMapper(ClientMapper.class);
try {
// 1. 【新增】
TblClient newClient = new TblClient();
newClient.setCname("王五");
newClient.setCaddress("广州");
newClient.setCbirthday(new Date());
mapper.insertClient(newClient);
System.out.println("✅ 插入成功");
// 2. 【查询】验证插入
List<TblClient> list = mapper.getClientAll();
list.forEach(c -> System.out.println(c.getCid() + "\t" + c.getCname()));
// 3. 【修改】假设修改刚插入的最后一条(取最大ID)
if (!list.isEmpty()) {
TblClient last = list.get(list.size() - 1);
last.setCaddress("深圳");
mapper.updateClient(last);
System.out.println("✅ 更新成功");
}
// 4. 【删除】删除刚插入的记录
if (!list.isEmpty()) {
Integer lastId = list.get(list.size() - 1).getCid();
mapper.deleteClientById(lastId);
System.out.println("✅ 删除ID=" + lastId + " 成功");
}
// ⚠️ 关键:提交事务!
session.commit();
System.out.println("✨ 所有操作已提交到数据库!");
} catch (Exception e) {
// 出错则回滚
session.rollback();
e.printStackTrace();
System.out.println("❌ 操作失败,已回滚!");
} finally {
MyBatisUtil.closeSqlSession(session);
}
}
}
✅ 最佳实践:
- 使用
try-catch-finally结构;- 成功时
commit(),异常时rollback();- 无论成功与否,最终都要
close()。
五、运行效果(示例)
控制台输出:
✅ 插入成功
1 张三
2 李四
3 王五
✅ 更新成功
✅ 删除ID=3 成功
✨ 所有操作已提交到数据库!
📸(可附上数据库前后对比截图,展示数据变化)
六、常见问题排查
❓ Q1:执行了 insert,但数据库没数据?
- 原因 :忘记调用
session.commit()。 - 解决:确保写操作后提交事务。
❓ Q2:报错 "ExecutorException: No constructor found"?
- 原因:实体类缺少无参构造方法。
- 解决 :为
TblClient添加public TblClient() {}(Lombok 用户注意@NoArgsConstructor)。
❓ Q3:如何获取自增主键(如 MySQL 的 ID)?
-
在
<insert>标签中添加:<insert id="insertClient" useGeneratedKeys="true" keyProperty="cid"> INSERT INTO tbl_client (...) VALUES (...) </insert>插入后,
client.getCid()即可获取生成的 ID。
七、总结
| 操作 | XML 标签 | 是否需要 commit | 注意事项 |
|---|---|---|---|
| SELECT | <select> |
否 | 只读,无需事务 |
| INSERT | <insert> |
是 | 可获取自增主键 |
| UPDATE | <update> |
是 | 注意 WHERE 条件 |
| DELETE | <delete> |
是 | 谨防误删 |
✨ 核心口诀 :
"查不用提,增删改要提;接口对 XML,事务不能离!"
本文完整演示了 MyBatis 基于接口的增删改查全流程。
下一篇我们将学习 动态 SQL(如
<if>、<where>) ,让 SQL 更灵活!欢迎点赞、收藏、评论交流 👍