博客做公司网站,百度开户怎么开,爱企查企业信息查询官网,江西建设厅网站证书查询项目中用到了MongoDB#xff0c;准备用来存储业务数据#xff0c;前提是要实现事务#xff0c;保证数据一致性#xff0c;MongoDB从4.0开始支持事务#xff0c;提供了面向复制集的多文档事务特性。能满足在多个操作#xff0c;文档#xff0c;集合#xff0c;数据库之间…项目中用到了MongoDB准备用来存储业务数据前提是要实现事务保证数据一致性MongoDB从4.0开始支持事务提供了面向复制集的多文档事务特性。能满足在多个操作文档集合数据库之间的事务性事务的特性。多文档事务在4.0版本仅支持复制集对分片集群的事务性支持计划在4.2版本中实现。由于我也算是一个java小白没怎么弄清java事务机制于是先建了个测试项目进行测试。在本例中可以看到多数据源下事务的使用请重点关注后面记录的爬坑记。Mongo Transaction项目介绍springboot 2.1.3MongoDB 4.0.3本项目主要为了测试MongoDB事务,由于正式项目还用了其它数据源所以加入了 Oracle, MySQL的事务包括多数据源的配置和使用使用说明1.导入MongoDB的依赖org.springframework.bootspring-boot-starter-data-mongodb2.配置MongoDB的连接spring:# mongodb 连接data:mongodb:uri: mongodb://192.168.0.68:27017,192.168.0.69:27017,192.168.0.70:27017/glcloud?replicaSetrs0database: glcloud3.编写entity类当id设置为 ObjectId 类型和添加 Id 注解时时MongoDB数据库会自动生成主键我们在保存对象时就不用设置id的值MongoUnit/*** 用户* author muyuer 182443947qq.com* version 1.0* date 2019-02-25 09:10*/DataDocument(collection test_unit)public class MongoUnit {private static final long serialVersionUID 1L;/*** Id*/Idprivate ObjectId id;/*** unitId*/private String unitId;/*** unitName*/private String unitName;}MongoUserpackage 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 182443947qq.com* version 1.0* date 2019-02-25 09:10*/DataDocument(collection test_user)public class MongoUser {private static final long serialVersionUID 1L;/*** Id*/Idprivate 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 182443947qq.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 182443947qq.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 182443947qq.com* version 1.0* date 2019-02-25 09:10*/ServiceSlf4jpublic class MongoUserServiceImpl implements MongoUserService {AutowiredMongoUserRepository mongoUserRepository;/*** 新增* param mongoUser* return*/Overridepublic R save(MongoUser mongoUser) {MongoUser mongoUserSave mongoUserRepository.save(mongoUser);log.info(用户信息保存testUserSave mongoUserSave);return RUtil.success();}OverrideTransactional(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 182443947qq.com* version 1.0* date 2019-02-25 09:10*/ServiceSlf4jpublic class MongoUnitServiceImpl implements MongoUnitService {AutowiredMongoUnitRepository mongoUnitRepository;AutowiredMongoUserService mongoUserService;/*** 新增** param unit* return*/Overridepublic R save(MongoUnit unit) {MongoUnit mongoUnitSave mongoUnitRepository.save(unit);log.info(单位信息保存testUnitSave mongoUnitSave);return RUtil.success();}OverrideTransactional(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.Controllerpackage 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 182443947qq.com* date 2019-02-25 10:59*/RestControllerSlf4jRequestMapping(pathtest/user)public class TestUserController {AutowiredMongoUserService mongoUserService;AutowiredPrimaryUserService primaryUserService;AutowiredSlaveUserService 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 182443947qq.com* date 2019-02-25 10:59*/RestControllerSlf4jRequestMapping(pathtest/unit)public class TestUnitController {AutowiredMongoUnitService mongoUnitService;AutowiredPrimaryUnitService primaryUnitService;AutowiredSlaveUnitService 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.02.MongoDB事务功能必须是在多副本集的情况下才能使用否则报错Sessions are not supported by the MongoDB cluster to which this client is connected4.2版本会支持分片事务。3.事务控制只能用在已存在的集合中也就是集合需要手工添加不会由jpa创建会报错Cannot create namespace glcloud.test_user in multi-document transaction.4.多数据源时需要指定事务 Transactional(value transactionManager) 如果只有1个数据源不需要指定value5.事务注解到类上时该类的所有 public 方法将都具有该类型的事务属性但一般都是注解到方法上便于实现更精确的事务控制6.事务传递性事务子方法上不必添加事务注解如果子方法也提供api调用可用注解propagation Propagation.REQUIRED也就是继承调用它的事务如果没有事务则新起一个事务7.启动类上的EnableTransactionManagement注解并不是像网上所说必需添加的注解因为spring boot 默认开始了这个注解的。8.有人说注解必须是Transactional(rollbackFor { Exception.class }) 测试并不需要rollbackFor { Exception.class },因为本例中自定义异常类继承自RuntimeException spring boot事物默认在遇到RuntimeException不论rollbackFor的异常是啥都会进行事务的回滚,加上rollbackForException.class,可以让事物在遇到非运行时异常时也回滚具体rollbackFor用法可参考:参考文档