官網:mongoDB中,對單文檔的操做是原子性的。例如insertOne
,updateOne
等操做。所以建議使用嵌入式文檔來實現事務需求,而不是規範化的跨文檔設計。可是業務上例如三方數據依賴的需求每每使用嵌入式文檔不是理想中的那麼方便。因此4.0開始提供了對副本集
多文檔事務的支持,注意是副本集
,也就是說單server
是不生效的。
接下來的測試須要集羣環境,賴得搭建,因此使用mongoDB Cloud提供的Altas
的免費集羣。java
<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>
這裏涉及到了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
@Configuration public class MongoTransactionConfiguration { @Bean MongoTransactionManager mongoTransactionManager(MongoDbFactory factory) { return new MongoTransactionManager(factory); } }
@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; }
@Data @Document(collection = "info") public class Info implements Serializable { private static final long serialVersionUID = 4494527542566322152L; private String username; private String description; }
@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; } }
@Slf4j @RestController public class MongoController { @Resource(name = "mongoService") private MongoService mongoService; @GetMapping("/transaction") public void updateWithTransaction() { mongoService.updateWithTransaction(); } }
能夠看到程序連上了集羣,而後在終端執行curl http://localhost:8080/transaction
能夠看到以下日誌mysql
最後查看mongoDB中的數據,能夠看到數據沒有被更改。web
上面建立的MongoService
中的updateWithTransaction
上添加了spring
提供的@Transactional
註解,因此mongoDB
的事務能夠和mysql
的事務統一管理。spring