mongoDB-40-事务

11次阅读

共计 2906 个字符,预计需要花费 8 分钟才能阅读完成。

官网:mongoDB 中,对单文档的操作是原子性的。例如 insertOneupdateOne 等操作。因此建议使用嵌入式文档来实现事务需求,而不是规范化的跨文档设计。但是业务上例如三方数据依赖的需求往往使用嵌入式文档不是理想中的那么方便。所以 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 的事务统一管理。

正文完
 0