官网:mongoDB中,对单文档的操作是原子性的。例如insertOne
,updateOne
等操作。因此建议使用嵌入式文档来实现事务需求,而不是规范化的跨文档设计。但是业务上例如三方数据依赖的需求往往使用嵌入式文档不是理想中的那么方便。所以4.0开始提供了对副本集
多文档事务的支持,注意是副本集
,也就是说单server
是不生效的。
接下来的测试需要集群环境,赖得搭建,所以使用mongoDB Cloud提供的Altas
的免费集群。
创建测试数据
- user
- info
创建springboot项目
添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
- 连接mongoDB
这里涉及到了Write Concern
,推荐阅读MongoDB writeConcern原理解析
w=majority:数据写入到副本集大多数成员后向客户端发送确认,适用于对数据安全性要求比较高的场景,该选项会降低写入性能
w=1:默认的writeConcern,数据写入到Primary就向客户端发送确认Read Concern
推荐阅读MongoDB readConcern 原理解析
spring.data.mongodb.uri=mongodb+srv://vulgar:761341@cluster0-t16it.mongodb.net/vulgar_test?retryWrites=true&w=majority
配置mongoDB事务管理
@Configuration
public class MongoTransactionConfiguration {
@Bean
MongoTransactionManager mongoTransactionManager(MongoDbFactory factory) {
return new MongoTransactionManager(factory);
}
}
创建对应实体类
- User.class
@Data
@Document(collection = "user")
public class User implements Serializable {
private static final long serialVersionUID = -7257487638617643262L;
private String username;
private String password;
private String sex;
private Integer age;
private String email;
}
- Info.class
@Data
@Document(collection = "info")
public class Info implements Serializable {
private static final long serialVersionUID = 4494527542566322152L;
private String username;
private String description;
}
创建测试SERVICE
@Slf4j
@Service("mongoService")
public class MongoService {
@Autowired
private MongoTemplate mongoTemplate;
@Transactional(rollbackFor = ArithmeticException.class)
public void updateWithTransaction() {
Query query = new Query(Criteria.where("username").is("vulgar-cd"));
Update update = new Update();
update.set("age", 10);
mongoTemplate.updateFirst(query, update, User.class);
User user = mongoTemplate.findOne(query, User.class);
log.info("user is {}", JSON.toJSON(user));
update = new Update();
update.set("description", "hahahaha");
mongoTemplate.updateFirst(query, update, Info.class);
Info info = mongoTemplate.findOne(query, Info.class);
log.info("info is {}", JSON.toJSON(info));
//测试事务回滚
int i = 1/0;
}
}
创建测试CONTROLLER
@Slf4j
@RestController
public class MongoController {
@Resource(name = "mongoService")
private MongoService mongoService;
@GetMapping("/transaction")
public void updateWithTransaction() {
mongoService.updateWithTransaction();
}
}
启动引用程序
可以看到程序连上了集群,然后在终端执行curl http://localhost:8080/transaction
可以看到如下日志
最后查看mongoDB中的数据,可以看到数据没有被更改。
上面创建的MongoService
中的updateWithTransaction
上添加了spring
提供的@Transactional
注解,所以mongoDB
的事务可以和mysql
的事务统一管理。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。