惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
L
LINUX DO - 最新话题
P
Privacy & Cybersecurity Law Blog
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
云风的 BLOG
云风的 BLOG
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
PCI Perspectives
PCI Perspectives
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
TaoSecurity Blog
TaoSecurity Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Attack and Defense Labs
Attack and Defense Labs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
小众软件
小众软件
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
F
Fortinet All Blogs
T
Threatpost
Security Latest
Security Latest
V
Vulnerabilities – Threatpost
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
WordPress大学
WordPress大学
Forbes - Security
Forbes - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
CERT Recently Published Vulnerability Notes
AI
AI
博客园 - 三生石上(FineUI控件)
T
Threat Research - Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Schneier on Security
I
Intezer
The GitHub Blog
The GitHub Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
V2EX
aimingoo的专栏
aimingoo的专栏
量子位
NISL@THU
NISL@THU
N
News and Events Feed by Topic
O
OpenAI News
Microsoft Azure Blog
Microsoft Azure Blog
C
Check Point Blog
Schneier on Security
Schneier on Security
S
Secure Thoughts
The Cloudflare Blog
J
Java Code Geeks

Chenxu's Blog

RAG检索优化:从 68% 到 82.2% 学习深度学习 北邮计算机研究生选课指北 学习机器学习 上海篇 提出一个好问题 写代码的环境 选购一台合适的设备 计算机的第零课 序言 内蒙古篇 山东篇 一篇对transformers的疑惑 浅析GPUStack 浅谈后端项目分层 浙江篇 河南篇 一些三端协同的开发工具记录 浅谈编程语言中的 GC 在 Windows 上安装 Rust 美化博客 消息队列 MyBatis 现代交换原理2024年题目 回忆版 北邮计科本科课程指北 ClkLog埋点用户分析系统研究报告 大数据梧桐实验分享 大数据HBase实验分享 国产向量数据库研究实践 —— 基于 Milvus 的电影推荐系统 服务器环境配置 大数据HDFS实验分享 SSE多服务之间推送数据 数据库系统原理 操作系统 编译原理 手把手教你gozero从开发到部署 (番外篇): 介绍 gtodolist 前端项目 天津篇 北京篇 手把手教你gozero从开发到部署 (5): gtodolist 之任务的删除 前端相关问题 vue3 + element-plus学习 git相关命令 人工智能原理 MySQL Redis 力扣刷题笔记之动态规划 记录一次 VSCode 出现的各种奇怪的问题 手把手教你gozero从开发到部署 (4): 在 model 中自己编写函数实现数据库分页查询 记录平时用到的 windows 右键管理 记录平时使用的 linux 的指令 安装 gstore 并使用 java api 手把手教你gozero从开发到部署 (3): gtodolist 之任务的创建和修改 手把手教你gozero从开发到部署 (番外篇): 记录第一次部署 CI/CD 的流程 记录完成 gtodolist 中遇到的 bug 手把手教你gozero从开发到部署 (2): gtodolist 之 user 模块开发 手把手教你gozero从开发到部署 (1): gtodolist 项目说明和环境准备 快速入门 gozero 框架 vue部署在nginx上的相关问题 记一次安装scrapy的报错 将博客部署至服务器 Java CS143: Compliers 《MySQL必知必会》读书笔记(2) 初识 GORM 初识 gin 框架 Spring 《MySQL必知必会》读书笔记(1) 本地搭建博客 🤝友链 🙋🏻‍♂️关于 Browser and Device Check
使用 MongoTemplate 时开启事务
Chenxu · 2023-11-24 · via Chenxu's Blog

最近有一个需求, 用户信息表内有一个唯一索引用户 id, 希望在插入时如果不存在该用户的信息则插入, 否则更新, 看了网上的方法, 似乎 MongoTemplate 并没有提供这项功能 (有类似的功能但只对主键 id 有效), 所以我选择了先删除, 再插入, 由此引发了我对事务的需求

修改 MongoDB 配置

MongoDB 的事务只能在开启副本集的时候才能使用,Windows 上的 MongoDB 安装后默认是单副本,所以我们首先需要将其转换为多副本.

找到 MongoDB 的安装目录, 在 bin 目录下有一个 mongod.cfg 配置文件, 在文件中增加配置:

replication:
    replSetName: rs0

然后重启 MongoDB, 以管理员身份运行终端:

net stop mongodb

net start mongodb

此时可以连上 MongoDB, 但是无法读取其中的数据, 所以需要初始化将其配置为副本集的成员, 在 MongoDB 的命令行界面执行以下命令 (这里使用 IDEA 提供的命令行):

# 初始化
rs.initiate()

# 查看状态
rs.status()

在 SpringBoot 中开启事务

先在配置文件中增加一项自定义配置, 这是为了兼容性

spring:
    data:
        mongodb:
            #      uri: mongodb://localhost/tcm
            host: localhost
            port: 27017
            database: test
            auto-index-creation: true
            transactionEnabled: true # 自定义配置, 打开事务

写配置类, 配置事务

@Configuration
public class MongoTransactionConfiguration {

    @Bean
    @ConditionalOnProperty(name = "spring.data.mongodb.transactionEnabled", havingValue = "true")
    MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory factory) {
        return new MongoTransactionManager(factory);
    }
}

然后在需要的方法上面加上 @Transactional 注解就可以开启事务啦

测试结果

@Override
@Transactional(rollbackFor = Exception.class)
public UserInfo saveUserInfo(UserInfo userInfo) {
    userInfo.setUpdateTime(DateUtil.getNowTime());

    Query q = Query.query(Criteria.where("userId").is(userInfo.getUserId()));
    UserInfo info = mongoTemplate.findOne(q, UserInfo.class);
    if (info != null) {
        userInfo.setId(info.getId());
        mongoTemplate.remove(q, UserInfo.class);
        int i = 1 / 0; // 报错测试事务效果

    }
    return mongoTemplate.save(userInfo);
}

可以看到报错以后执行事务回滚, 并没有删除原来的 userId 为 1 的数据