jcalaBlog 事务管理指南:@Transactional 在博客发布中的正确用法
【免费下载链接】jcalaBloga personal blog site based on springboot+srpingMVC+mybatis+velocity+bootstrap+mysql项目地址: https://gitcode.com/gh_mirrors/jc/jcalaBlog
jcalaBlog 是一个基于 Spring Boot + MyBatis + MySQL 的个人博客系统,后台发布一篇博客并非"插一条数据"那么简单,而是涉及文章表和标签表的多步写入。这篇文章就是一份面向新手的 Spring Boot 事务管理指南:我们以 jcalaBlog 的博客发布流程为例,一步步拆解 @Transactional 注解的正确用法,帮你彻底搞懂"为什么需要事务"以及"如何配置事务才不出错",从此告别数据不一致的烦恼。🧑💻
一、为什么博客发布必须依赖事务?🛡️
在 jcalaBlog 的后台,点击"发布"按钮提交一篇博客时,服务层其实要连续完成两次数据库写入:
- 把文章标题、正文、Markdown 源码插入
blog_view文章表 - 把文章对应的标签逐条插入
view_tag标签表
如果第二步在中途失败,就会出现"文章在、标签丢"的脏数据,读者点开文章却看不到分类标签,后台管理也会错乱。事务(Transaction)的价值就是把这两步打包成一个不可分割的整体:要么全部成功提交,要么全部失败回滚,从而保证数据一致性。这正是 Spring Boot 事务管理要解决的核心问题。
二、jcalaBlog 中 @Transactional 用在哪里?🔍
打开 BlogSerImpl.java 就能看到,所有涉及多表写入的方法都加上了@Transactional注解:
| 方法 | 事务注解 | 涉及的表操作 |
|---|---|---|
addBlog发布博客 | ✅@Transactional | 插入文章 + 插入标签 |
updateBlog更新博客 | ✅@Transactional | 更新文章 + 重建标签 |
deleteBlogById删除博客 | ✅@Transactional | 删除文章记录 |
同样的做法也出现在 InfoSerImpl.java 的修改密码、ProjectSerImpl.java 的新增项目等方法中。规律很简单:只要一个方法里有多条 SQL 写入,就值得用事务包起来。
三、addBlog 发布博客的完整事务流程 📋
我们以最典型的addBlog方法为例,看看 jcalaBlog 是如何用事务组织一次博客发布的:
@Transactional(isolation = Isolation.READ_COMMITTED) public void addBlog(BlogView blogView){ blogView.setDate(new Date(System.currentTimeMillis())); blogMapper.insertBlog(blogView); // ① 插入文章 addViewTag(blogView.getTags(), blogView.getVid()); // ② 插入标签 }这里有一个特别值得新手留意的细节:第①步插入文章时,BlogMapper.java 通过@SelectKey配合LAST_INSERT_ID()把自增主键回填给blogView.getVid(),第②步插入标签时正好复用这个新文章的 ID。
也就是说,标签和文章通过主键强关联。一旦第②步出错,第①步的"半成品文章"也必须一并撤销,否则就会产生孤儿数据。没有@Transactional,这两步就是两条独立的 SQL,后果不堪设想。
四、为什么选择 READ_COMMITTED 隔离级别?🎯
细心的你可能注意到,jcalaBlog 的每个事务注解都明确指定了isolation = Isolation.READ_COMMITTED。数据库事务有四种隔离级别,从低到高依次为:
- READ UNCOMMITTED:能读到未提交的数据,可能产生脏读 ❌
- READ COMMITTED:只能读到已提交的数据,杜绝脏读 ✅
- REPEATABLE READ:同一事务内多次读取结果一致(MySQL 默认级别)
- SERIALIZABLE:串行执行,性能开销最大 ⚠️
jcalaBlog 选择READ_COMMITTED是很务实的决定:博客系统是高并发读、低频写的场景,既要避免读到别人未提交的脏数据,又不想为了"可重复读"付出额外的锁开销。数据源配置在 application-dev.yml,基于 HikariCP 连接池连接 MySQL,这套"读已提交"策略足以满足个人博客对数据一致性和性能的双重要求。
五、更新与删除博客时的事务处理 ♻️
发布之外,updateBlog和deleteBlogById同样是事务的用武之地。
updateBlog的逻辑是:先更新文章表内容,再deleteViewTag清空旧标签,最后重新insertViewTag写入新标签。删除 + 插入标签必须是原子的——如果删掉了旧标签却没能写入新标签,文章就变成了"无标签孤儿"。而deleteBlogById删除文章时,事务保证了删除操作要么完整生效、要么完全不生效,不会留下残缺记录。前后端调用链可参考 BlogCtrl.java 中的postAction、update和delete三个控制器方法。
六、使用 @Transactional 的三个避坑要点 ⚠️
光会加注解还不够,新手最容易踩的坑有以下三个:
- 自调用会让事务失效:
@Transactional依赖 Spring AOP 代理,如果在同一个类内部通过this.xxx()调用事务方法,代理不会生效。请确保事务方法由外部 Bean 调用。 - 默认只回滚运行时异常:注解默认对
RuntimeException(如空指针、SQL 异常)回滚,如果方法里捕获了受检异常还想要回滚,需要显式指定rollbackFor = Exception.class。 - 读操作不必加事务:jcalaBlog 对查询类方法(如
getTagList、getArchive)用@Cacheable做缓存,而不是加事务,这样既保证了速度又避免了无谓的连接占用。事务用在"写",缓存用在"读",这是很好的工程习惯。
七、动手验证:把 jcalaBlog 跑起来 🚀
纸上得来终觉浅,想亲手验证事务效果,可以这样快速起步:
git clone https://gitcode.com/gh_mirrors/jc/jcalaBlog项目根目录自带 docker-compose.yml,配合 MySQL 即可一键启动。默认后台地址/admin,初始账号admin、密码admin(详见 README.md)。登录后试着发布一篇带多个标签的博客,然后在blog_view与view_tag两张表里核对数据,你就能直观感受到事务带来的数据一致性保障。💪
总结 ✅
通过 jcalaBlog 这个真实项目,我们完整走了一遍 Spring Boot 事务管理的核心用法:发布博客的多表写入离不开 @Transactional,READ_COMMITTED 是兼顾一致性与性能的合理选择,注解的正确使用还要避开自调用和异常回滚的坑。掌握了这些,你的 Spring Boot 博客开发之路会顺畅许多。
【免费下载链接】jcalaBloga personal blog site based on springboot+srpingMVC+mybatis+velocity+bootstrap+mysql项目地址: https://gitcode.com/gh_mirrors/jc/jcalaBlog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考