MySQL调用mongodb事务回滚_SpringBoot整合MongoDB,在多数据源下实现事务回滚。

项目中用到了MongoDB,准备用来存储业务数据,前提是要实现事务,保证数据一致性,MongoDB从4.0开始支持事务,提供了面向复制集的多文档事务特性。能满足在多个操作,文档,集合,数据库之间的事务性,事务的特性。多文档事务在4.0版本仅支持复制集,对分片集群的事务性支持计划在4.2版本中实现。由于我也算是一个java小白,没怎么弄清java事务机制,于是先建了个测试项目进行测试。在本例中可以看到多数据源下事务的使用,请重点关注后面记录的爬坑记。

Mongo Transaction

项目介绍

springboot 2.1.3

MongoDB 4.0.3

本项目主要为了测试MongoDB事务,由于正式项目还用了其它数据源,所以加入了 Oracle, MySQL的事务,包括多数据源的配置和使用

使用说明

1.导入MongoDB的依赖

org.springframework.boot

spring-boot-starter-data-mongodb

2.配置MongoDB的连接

spring:

# mongodb 连接

data:

mongodb:

uri: mongodb://192.168.0.68:27017,192.168.0.69:27017,192.168.0.70:27017/glcloud?replicaSet=rs0

database: glcloud

3.编写entity类

当id设置为 ObjectId 类型和添加 @Id 注解时时,MongoDB数据库会自动生成主键,我们在保存对象时就不用设置id的值

MongoUnit

/**

* 用户

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

@Data

@Document(collection = "test_unit")

public class MongoUnit {

private static final long serialVersionUID = 1L;

/**

* Id

*/

@Id

private ObjectId id;

/**

* unitId

*/

private String unitId;

/**

* unitName

*/

private String unitName;

}

MongoUser

package com.example.demo.entity.mongo;

import lombok.Data;

import org.bson.types.ObjectId;

import org.springframework.data.annotation.Id;

import org.springframework.data.mongodb.core.mapping.Document;

/**

* 用户

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

@Data

@Document(collection = "test_user")

public class MongoUser {

private static final long serialVersionUID = 1L;

/**

* Id

*/

@Id

private ObjectId id;

/**

* userId

*/

private String userId;

/**

* userName

*/

private String userName;

/**

* unitId 关联testUser

*/

private String unitId;

}

4.编写dao层的方法

只需继承MongoRepository即可。

package com.example.demo.repository.mongo;

import com.example.demo.entity.mongo.MongoUser;

import org.springframework.data.mongodb.repository.MongoRepository;

/**

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

public interface MongoUserRepository extends MongoRepository {

}

package com.example.demo.repository.mongo;

import com.example.demo.entity.mongo.MongoUnit;

import org.springframework.data.mongodb.repository.MongoRepository;

/**

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

public interface MongoUnitRepository extends MongoRepository {

}

5.Service层

package com.example.demo.service.mongo.impl;

import com.example.demo.common.SystemException;

import com.example.demo.entity.mongo.MongoUser;

import com.example.demo.repository.mongo.MongoUserRepository;

import com.example.demo.service.mongo.MongoUserService;

import com.example.demo.common.R;

import com.example.demo.common.RUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Propagation;

import org.springframework.transaction.annotation.Transactional;

/**

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

@Service

@Slf4j

public class MongoUserServiceImpl implements MongoUserService {

@Autowired

MongoUserRepository mongoUserRepository;

/**

* 新增

* @param mongoUser

* @return

*/

@Override

public R save(MongoUser mongoUser) {

MongoUser mongoUserSave = mongoUserRepository.save(mongoUser);

log.info("用户信息保存:testUserSave = "+ mongoUserSave);

return RUtil.success("");

}

@Override

@Transactional(value = "MONGO_TRANSACTION_MANAGER", propagation = Propagation.REQUIRED)

public R bathSave(String unitId, Boolean rollBack) {

for (int i = 0; i <= 10; i++) {

//注释这段则可以正常添加数据,测试回滚则throw异常信息

if (unitId.equals("003") && rollBack) {

throw new SystemException("测试回滚故意抛出的异常");

}

MongoUser user = new MongoUser();

user.setUserId(unitId + "U0" + i);

user.setUserName("用户" + i);

user.setUnitId(unitId);

save(user);

}

return RUtil.success("");

}

}

package com.example.demo.service.mongo.impl;

import com.example.demo.enums.REnum;

import com.example.demo.common.SystemException;

import com.example.demo.entity.mongo.MongoUnit;

import com.example.demo.repository.mongo.MongoUnitRepository;

import com.example.demo.service.mongo.MongoUnitService;

import com.example.demo.service.mongo.MongoUserService;

import com.example.demo.common.R;

import com.example.demo.common.RUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

/**

* @author muyuer 182443947@qq.com

* @version 1.0

* @date 2019-02-25 09:10

*/

@Service

@Slf4j

public class MongoUnitServiceImpl implements MongoUnitService {

@Autowired

MongoUnitRepository mongoUnitRepository;

@Autowired

MongoUserService mongoUserService;

/**

* 新增

*

* @param unit

* @return

*/

@Override

public R save(MongoUnit unit) {

MongoUnit mongoUnitSave = mongoUnitRepository.save(unit);

log.info("单位信息保存:testUnitSave = " + mongoUnitSave);

return RUtil.success("");

}

@Override

@Transactional(value = "MONGO_TRANSACTION_MANAGER")

public R bathSave(Boolean rollBack) {

try {

for (int i = 0; i < 4; i++) {

MongoUnit unit = new MongoUnit();

unit.setUnitId("00" + i);

unit.setUnitName("单位" + i);

mongoUserService.bathSave(unit.getUnitId(),rollBack);

save(unit);

}

return RUtil.success("");

} catch (SystemException e) {

log.error("保存数据失败:msg: {}", e.getMessage());

throw new SystemException(REnum.ERROR.getCode(), "保存数据失败 Error:" + e.getMessage());

}

}

}

6.Controller

package com.example.demo.controller;

import com.example.demo.enums.DbTypeEnum;

import com.example.demo.service.mongo.MongoUserService;

import com.example.demo.common.R;

import com.example.demo.service.primary.PrimaryUserService;

import com.example.demo.service.slave.SlaveUserService;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

/**

* @author muyuer 182443947@qq.com

* @date 2019-02-25 10:59

*/

@RestController

@Slf4j

@RequestMapping(path="test/user")

public class TestUserController {

@Autowired

MongoUserService mongoUserService;

@Autowired

PrimaryUserService primaryUserService;

@Autowired

SlaveUserService slaveUserService;

/**

* 新增

* @param dbType

* @param unitId

* @param rollBack

* @return

*/

@PostMapping("/bathSave/{dbType}/{unitId}/{rollBack}")

public R bathSave(@PathVariable DbTypeEnum dbType, @PathVariable String unitId, @PathVariable Boolean rollBack){

switch (dbType) {

case MONGO:

return mongoUserService.bathSave(unitId, rollBack);

case PRIMARY:

return primaryUserService.bathSave(unitId, rollBack);

default:

return slaveUserService.bathSave(unitId, rollBack);

}

}

}

package com.example.demo.controller;

import com.example.demo.enums.DbTypeEnum;

import com.example.demo.service.mongo.MongoUnitService;

import com.example.demo.common.R;

import com.example.demo.service.primary.PrimaryUnitService;

import com.example.demo.service.slave.SlaveUnitService;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

/**

* @author muyuer 182443947@qq.com

* @date 2019-02-25 10:59

*/

@RestController

@Slf4j

@RequestMapping(path="test/unit")

public class TestUnitController {

@Autowired

MongoUnitService mongoUnitService;

@Autowired

PrimaryUnitService primaryUnitService;

@Autowired

SlaveUnitService slaveUnitService;

/**

* 新增

* @param dbType 数据库

* @param rollBack 是否回滚

* @return

*/

@PostMapping("/bathSave/{dbType}/{rollBack}")

public R bathSave(@PathVariable DbTypeEnum dbType, @PathVariable Boolean rollBack) {

switch (dbType) {

case MONGO:

return mongoUnitService.bathSave(rollBack);

case PRIMARY:

return primaryUnitService.bathSave(rollBack);

default:

return slaveUnitService.bathSave(rollBack);

}

}

}

测试

PostMan post 地址

在实际应用中爬过的坑

1.MongoDB的版本必须是4.0

2.MongoDB事务功能必须是在多副本集的情况下才能使用,否则报错"Sessions are not supported by the MongoDB cluster to which this client is connected",4.2版本会支持分片事务。

3.事务控制只能用在已存在的集合中,也就是集合需要手工添加不会由jpa创建会报错"Cannot create namespace glcloud.test_user in multi-document transaction."

4.多数据源时需要指定事务 @Transactional(value = "transactionManager") 如果只有1个数据源不需要指定value

5.事务注解到类上时,该类的所有 public 方法将都具有该类型的事务属性,但一般都是注解到方法上便于实现更精确的事务控制

6.事务传递性,事务子方法上不必添加事务注解,如果子方法也提供api调用可用注解propagation = Propagation.REQUIRED也就是继承调用它的事务,如果没有事务则新起一个事务

7.启动类上的@EnableTransactionManagement注解,并不是像网上所说必需添加的注解,因为spring boot 默认开始了这个注解的。

8.有人说:注解必须是@Transactional(rollbackFor = { Exception.class }) 测试并不需要rollbackFor = { Exception.class },因为本例中自定义异常类继承自RuntimeException spring boot事物默认在遇到RuntimeException不论rollbackFor的异常是啥,都会进行事务的回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚

具体rollbackFor用法可参考:

参考文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Goreplay来做流量回放

最近做项目&#xff0c;用到goreplay来做流量回放&#xff0c;什么是goreplay&#xff1f;GoReplay is an open-source network monitoring tool which can record your live traffic, and use it for shadowing, load testing, monitoring and detailed analysis.本质上就是通…

硬盘知识学习(一)

硬盘相关常识&#xff08;一&#xff09;一、硬盘的组成硬盘粗略的讲&#xff0c;包括碟片、磁头&#xff0c;主轴、接口、缓存等组成。二、硬盘的三个基本概念1&#xff0c;什么是磁道&#xff08;TRACK&#xff09;。磁道首先是看不到的。他是在格式化的时候在盘面上划分出的…

“Python简直万能!”拜托快醒醒!

全世界只有3.14 % 的人关注了爆炸吧知识在程序员中&#xff0c;一直流传着“Python除了不会生孩子&#xff0c;什么都会”的传说&#xff0c;Python真的是万能语言&#xff1f;很多使用Python的小伙伴&#xff0c;坚信 Python 可以做任何事情。到底是不是真的如传说中那般万能&…

如何对 string 进行Base64编码,解码?

咨询区 Kevin Driedger&#xff1a;如何将指定的 string 编码成 base64。如何将 base64 解码成 string。回答区 andrew.fox&#xff1a;我来分享下对这个问题的处理吧&#xff1a;对 Encoding 类进行扩展&#xff0c;当然扩展方法还支持各种编码格式&#xff0c;不仅仅是 UTF8。…

python编程自然数表达式_[宜配屋]听图阁

普通的数学运算用这个纯抽象的符号演算来定义&#xff0c;计算结果只能在脑子里存在。所以写了点代码&#xff0c;来验证文章中介绍的演算规则。我们来验证文章里介绍的自然数及自然数运算规则。说到自然数&#xff0c;今天还百度了一下&#xff0c;据度娘说&#xff0c;1993年…

Oracle分区表常用命令

一、Oracle分区简介 ORACLE的分区是一种处理超大型表、索引等的技术。分区是一种“分而治之”的技术&#xff0c;通过将大表和索引分成可以管理的小块&#xff0c;从而避免了对每个表作为一个大的、单独的对象进行管理&#xff0c;为大量数据提供了可伸缩的性能。分区通过将操作…

linux--web服务器

WEB服务器也称为WWW(WORLD WIDE WEB)服务器&#xff0c;主要功能是提供网上信息浏览服务。 WWW 是 Internet的多媒体信息查询工具&#xff0c;是 Internet 上近年才发展起来的服务&#xff0c;也是发展最快和目前用的最广泛的服务。1.rpm -qa|grep httpd 查询服务是否安装…

WPF轮播图实现方式

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织欢迎转发、分享、点赞、在看&#xff0c;谢谢~。 01—效果预览效果预览&#xff08;更多效果请下载源码体验&#xff09;&#xff1a;02—代码如下一、MasterCarousel.cs 代码如下using System; …

学过物理的人才能看懂的笑话,你能看明白几个?

全世界只有3.14 % 的人关注了爆炸吧知识1丈夫买了几斤廉价藕&#xff0c;满以为可对妻子炫耀了。不料妻子破口大骂&#xff1a;笨蛋&#xff01;为何不买别的菜&#xff0c;这藕一斤少说也有半斤窟窿啊&#xff01;还说便宜&#xff1f;2第一次坐飞机的两位老妇人在飞机起飞前找…

QtWebkit中浏览器插件的设计-1

我们都知道浏览器中有一套由Netscape浏览器传承下来的插件接口&#xff0c;包括webkit&#xff0c;firefox都是支持的&#xff0c;但是那个开发起来比较困难&#xff0c;并且是平台相关的&#xff0c;借助于Qt的跨平台的特性&#xff0c;可以方便地为Qt开发出一套跨平台的插件。…

mysql左键关联_MySQL的:左键删除重复列加入,3个表

我有一个表,使用3个外键到其他表.当我执行左连接时,我会收到重复的列.MySQL表示,USING语法将减少重复的列,但没有多个键的示例.鉴于&#xff1a;mysql> describe recipes;---------------------------------------------------------------| Field | Type | Null | Key | De…

cisco 双ISP线路接入,链路自动切换方案

最近接到的一个项目&#xff0c;客户总部在惠州&#xff0c;分部在香港&#xff0c;在香港分部设有ERP服务器与邮件服务器&#xff0c;总部出口为铁通10M光纤与网通1M DDN 专线&#xff08;新增&#xff09;&#xff0c;原总部是用netscreen 防火墙与香港的pix 515作IPsec 对接…

js遮罩层以及移动端的上拉框

今天发一个之前写的移动端的项目&#xff0c;主要是讲一下遮罩层的应用&#xff0c;以及顺带提一下移动开发的一些事情。首先按钮点击弹出遮罩层这个大家很熟悉了&#xff0c;这里还是给大家提供一份代码&#xff0c;跟通用的没太大区别&#xff0c;主要讲一下方法&#xff1a;…

精简ABP的模块依赖

ABP的模块非常方便我们扩展自己的或使用ABP提供的模块功能&#xff0c;对于ABP自身提供的模块间的依赖关系想一探究竟&#xff0c;并且试着把不必要的模块拆掉&#xff0c;找到那部分核心模块。本次使用的是AspNetBoilerplate。源码下载从Github下载ABP源码后&#xff0c;进入s…

你这飞机会爆炸吗?航空公司含泪甩卖49元机票,却被超模君挖出秘密!

全世界只有3.14 % 的人关注了爆炸吧知识制作团队制作人 超模君编剧 恐恐恐插画 杨羊羊 友情出演 超模君 章小天……小天吐槽时刻……超模君之后还会采访谁呢小天有小道消息哦扫描这个二维码你将会有机会见识到超模君的科普沙雕网友们一起斗图↓↓↓↓…

[zz]WCF分布式开发步步为赢(0):WCF学习经验分享,如何更好地学习WCF?

WCF分布式开发学习&#xff0c;应该从哪里开始? 学习WCF是不是就不需要学习Enterprise Sevices(COM).Net Remoting、Web Service(ASMX)、WSE3.0和MSMQ消息队列&#xff1f; WCF分布式开发学习&#xff0c;如何制定一个合理的计划&#xff0c;才能更好地学习WCF分布式应用开…

C#报错:创建调试信息文件 ……obj\Debug\model.pdb: 拒绝访问

错误&#xff1a;创建调试信息文件“.......\obj\Debug\model.pdb”时发生错误 --“......\obj\Debug\model.pdb: 拒绝访问。 解决办法如下&#xff1a; 删除该项目下的 bin 和 obj 文件夹 就可以了,然后右键项目名点生成&#xff0c;就会重新生成bin和obj文件夹。

linux nginx mysql php 5.5._搭建基于Linux6.3+Nginx1.2+PHP5+MySQL5.5的Web服务器全过程

之前的Web服务器都是通过yum搭建的&#xff0c;想要添加新模块或者更新某些软件都很不方便(牵一发而动全身啊&#xff01;)。所以&#xff0c;现在准备将环境改为源码编译安装&#xff0c;这样便于调整&#xff0c;性能上也会比yum方式好很多。以下是我的安装步骤&#xff0c;我…

ASP 缩略图 (纠错版)

网上很多缩略的代码&#xff0c;不过很多都是错误的。 这个是纠正版&#xff0c;本人已修改。 Code<%Function PicReSize(picURL)FileName1Mid(picURL,13,22)Set Jpeg Server.CreateObject("Persits.Jpeg") 获取源图片路径Path Server.MapPath(picURL) 打开源图…

Blazor Server 应用程序中进行 HTTP 请求

翻译自 Waqas Anwar 2021年5月4日的文章 《Making HTTP Requests in Blazor Server Apps》 [1]Blazor Server 应用使用标准的 ASP.NET Core 应用程序&#xff0c;在服务端执行 .NET 代码。在 Blazor Server 应用程序中&#xff0c;我们可以像在 ASP.NET Core Web 应用程序中那样…