2026/09/07笔记

事务的使用:

一、@Transactional 注解:

AOP代码实现的:在调用this.syncLocal(incoming))方法的前后,开启和提交事务。

调用方

→ Spring 代理对象.method()

→ 拦截器:开启事务

→ 真正执行目标方法

→ 拦截器:提交 / 回滚

二、transactionTemplate (精细化给某段代码加事务控制)

TransactionTemplate 是编程式开启,不依赖代理,私有方法里也能用。

  1. TransactionManager.getTransaction() // 开启事务、绑定到当前线程

  2. 执行 syncLocal(...) // 里面的 JDBC/MyBatis 自动加入这个事务

  3. commit(成功)或 rollback(异常)

@Override

public void fullSync() {

SingleCellDataPermissionHelper.ignore(() -> {

List<CellSingleLimsTrialGroup> incoming = loadFromLims();

if (CollectionUtils.isEmpty(incoming)) {

throw new ServiceException("LIMS部门数据为空,终止同步");

}

transactionTemplate.executeWithoutResult(status -> syncLocal(incoming));

cellSingleLimsTrialGroupTreeCache.refresh();

});

}

//不能使用@Transactional注解会失效

private void syncLocal(List<CellSingleLimsTrialGroup> incoming) {

Map<Long, CellSingleLimsTrialGroup> incomingMap = toIdMap(incoming);

Map<Long, CellSingleLimsTrialGroup> existingMap = toIdMap(cellSingleLimsTrialGroupDao.selectAllKeys());

List<CellSingleLimsTrialGroup> toInsert = new ArrayList<>();

List<CellSingleLimsTrialGroup> toUpdate = new ArrayList<>();

List<Long> toDelete = new ArrayList<>();

for (Map.Entry<Long, CellSingleLimsTrialGroup> entry : incomingMap.entrySet()) {

if (existingMap.containsKey(entry.getKey())) {

toUpdate.add(entry.getValue());

} else {

toInsert.add(entry.getValue());

}

}

for (Map.Entry<Long, CellSingleLimsTrialGroup> entry : existingMap.entrySet()) {

if (!incomingMap.containsKey(entry.getKey())) {

toDelete.add(entry.getKey());

}

}

if (CollectionUtils.isNotEmpty(toDelete)) {

cellSingleLimsTrialGroupDao.deleteByIds(toDelete);

}

if (CollectionUtils.isNotEmpty(toUpdate)) {

cellSingleLimsTrialGroupDao.updateByIds(toUpdate);

}

if (CollectionUtils.isNotEmpty(toInsert)) {

cellSingleLimsTrialGroupDao.insertBatch(toInsert);

}

log.info("检测部门树全量同步完成, incoming={}, insert={}, update={}, delete={}",

incomingMap.size(), toInsert.size(), toUpdate.size(), toDelete.size());

}

相关推荐
志尊宝1 小时前
Vue3 零基础每日笔记(005):ref 响应式基础——为什么 script 里要 .value
前端·javascript·vue.js·笔记
点心的游戏开发世界2 小时前
GDScript 入门笔记(十六):文件读写与数据持久化
开发语言·笔记·游戏引擎·godot
ByNotD0g3 小时前
跨站脚本攻击- XSS
笔记·web安全
摇滚侠3 小时前
《Spring Boot 3:高级与架构设计》第 1 章 BeanDefinitionRegistry 阅读笔记 3
spring boot·笔记·后端
東隅已逝,桑榆非晚3 小时前
c++内存管理
c++·笔记
clorinda3 小时前
PyTorch 手写数字识别学习笔记
pytorch·笔记·学习
点心的游戏开发世界3 小时前
GDScript 入门笔记(十三):字符串操作
开发语言·笔记·游戏引擎·godot
点心的游戏开发世界4 小时前
GDScript 入门笔记(十二):类型系统进阶
笔记·游戏引擎·godot
LuminousCPP4 小时前
数据结构-排序(一):基础排序算法横向对比|冒泡、插入、希尔、堆与双向选择,详解二分 / Knuth 增量
c语言·数据结构·笔记·算法·排序算法