mongoDB 4.0 事務

官網:mongoDB中,對單文檔的操作是原子性的。例如
insertOne
updateOne等操作。因此建議使用嵌入式文檔來實現事務需求,而不是規範化的跨文檔設計。但是業務上例如三方數據依賴的需求往往使用嵌入式文檔不是理想中的那麼方便。所以4.0開始提供了對
副本集多文檔事務的支持,注意是
副本集,也就是說
單server是不生效的。

接下來的測試需要集群環境,賴得搭建,所以使用mongoDB Cloud提供的Altas的免費集群。

創建測試數據

  • user

《mongoDB 4.0 事務》

  • info

《mongoDB 4.0 事務》

創建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();
    }
}

啟動引用程序

《mongoDB 4.0 事務》

可以看到程序連上了集群,然後在終端執行curl http://localhost:8080/transaction可以看到如下日誌

《mongoDB 4.0 事務》
最後查看mongoDB中的數據,可以看到數據沒有被更改。

上面創建的MongoService中的updateWithTransaction上添加了spring提供的@Transactional註解,所以mongoDB的事務可以和mysql的事務統一管理。

点赞

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *