当前位置: 首页 > 科技观察

MySQLVKMongoDB:多文档事务支持,谁更友好?

时间:2023-03-16 17:46:01 科技观察

MongoDB4.0已经发布GA版本,有很多新特性和改进。在本文中,我们将重点关注主要功能,这无疑是对多文档ACID事务的支持。我们将隔离级别、可重复读、幻读、事务冲突检测等主要功能通过实验与MySQL一一对比。首先会简单介绍一下ACID事务隔离级别,然后进入测试主题正文。原子性:事务中包含的所有操作要么成功要么失败,没有半成功的概念。“西方二元对立-非此即彼”的典型例子:在二元逻辑体系中,只有两种逻辑值,即对与错,或正与负,没有对与错或既不正也不负的其他地位。一致性:事务在执行前后必须处于一致的状态。典型例子:“金龙,你借我5000元,我下个月还你。”不管金龙用什么方式给我转钱,转几次。贷款结束后,我银行卡里的余额会增加5000元。钱包里少了5000块钱,10000块钱也突然冒不出来。隔离性:数据库使用锁机制来实现事务隔离。当多个事务同时更新数据库中的同一个数据时,只有持有锁的事务被允许更新数据,其他事务必须等到前一个事务释放锁,其他事务才有机会更新数据。典型例子:“去医院看病,还要去找护士分诊排队,如果多个病人同时进来,医生会气得出去排队。你只能一个一个看。”持久性:事务提交成功后,对数据库所做的修改永久保存。即使数据库崩溃,数据也可以恢复到事务提交成功后的状态。典型例子:“你去ATM机取钱,ATM机出故障了,你把钱取了,卡里的余额不能减。”一、限制与限制1、多文档事务只适用于副本集。注意:如果是单机,需要切换到副本集模式。2.仅适用于WiredTiger存储引擎。3.如果你的架构是Sharding模式,不支持事务。计划在4.2版本中支持分布式事务。4、事务只支持CRUD操作,不支持DDL和DCL操作。注:CRUD是MySQL的DML,含义相同,名称不同。5.无法在config、admin和本地系统数据库中读取或写入事务。6.交易不能写入system.*(系统集合)。7、不能写入大事务,写集不能超过16MB(类似MariaDBGaleraCluster写集wsrep_max_ws_size限制),否则客户端会直接报错。注意:如果您有大笔交易,您应该考虑将这些大笔交易拆分成几个较小的交易。比如把大于2018的status值改成1,就要考虑批量更新10000条记录,和MySQL的方法一样。其次,我们的第一个事务必须在开始事务之前创建一个会话。事务不能在会话之外运行。varsession1=db.getMongo().startSession()varsession2=db.getMongo().startSession()MongoShell引入了三个用于创建、提交和终止事务的新命令:session.startTransaction()在当前会话中启动事务会话。commitTransaction()持久化事务中的操作改变session.abortTransaction()终止事务操作所做的改变1.在test数据库中创建一张t1表,插入4条数据。Demo1Demo2空闲事务受transactionLifetimeLimitSeconds参数的影响,该参数默认为60秒。可以通过以下命令查看:db.adminCommand({getParameter:1,transactionLifetimeLimitSeconds:1})如果要在线更改,可以通过以下命令设置:db.adminCommand({setParameter:1,transactionLifetimeLimitSeconds:30})也可以在/etc/mongod.cnf配置文件中写Dead***valid,格式如下:setParameter=transactionLifetimeLimitSeconds=30注意:Idletransaction是指当一个事务长时间没有提交时间,则连接无法关闭,内存也不会被释放。大量并发会导致DB连接数增加,对性能有影响。默认为60秒,可以根据自己的情况设置阈值。超过这个阈值,服务器会自动终止未提交的空闲事务。三、事务隔离演示演示一:事务冲突检测当两个(或多个)并发事务修改同一个文档时,就会发生冲突。MongoDB可以立即检测到冲突,即使事务尚未提交。这与MySQL有些不同。MySQL可以通过参数innodb_lock_wait_timeout检测到事务冲突后自动终止回滚时间,而MongoDB没有提供该参数。执行索引创建时,不添加{background:1})在后台创建。此时,新事务将无法获取到所需的锁,等待参数maxTransactionLockRequestTimeoutMillis后,事务将被终止并回滚。默认值为5毫秒。如果想在线调整事务等待获取锁的时间,可以通过以下命令设置:db.adminCommand({setParameter:1,maxTransactionLockRequestTimeoutMillis:15})也可以硬编码在/etc/mongod.cnf配置文件***生效,格式如下:setParameter=maxTransactionLockRequestTimeoutMillis=15演示2:可重复读可重复读(repeatableread)可以避免脏读和不可重复读的发生。不可重复读侧重于更新和修改数据,即在同一个事务中,两次查询的数据结果不一致。与脏读的区别在于:脏读是一个事务读取另一个事务未提交的脏数据。示范三:幻读在MySQL默认的隔离级别RepeatableRead下,刚才的操作会莫名其妙的看到session2未提交事务中的第五条数据,这种现象称为幻读。幻读和不可重复读很相似,只不过幻读重在增删改查,而不可重复读重在变化。常见的是一个事务中两次查询得到的数据结果不一致。因此,从测试结果得出的结论是,MongoDB默认采用的隔离级别是Snapshot一致性快照(尤其是当设置了readConcern=majority时,读取一行数据的历史版本时,依赖于这个隔离级别。)Snapshot介于RepeatableRead和Serializable之间。既避免了脏读、不可重复读、幻读,又不会因为Serializable序列化而降低并发性能。参考资料https://docs.mongodb.com/manual/core/transactions/https://www.percona.com/blog/2018/12/04/mongodb-4-0-using-acid-multi-document-transactions/