- 快召唤伙伴们来围观吧
- 微博 QQ QQ空间 贴吧
- 文档嵌入链接
- 复制
- 微信扫一扫分享
- 已成功复制到剪贴板
Transactions With MongoDB Shell
事务是RDBMS系统的一个特性,但MongoDB是一个面向文档的非RDBMS数据库。它以简单的数据导入和跨多个服务器的数据分片而闻名。在MongoDB 4.0中,在一个复制集环境中引入了一个新的功能多文档事务,我们将探讨应用程序如何使用MongoDB来适应这个新功能。本次网络研讨会还将研究MongoDB中的事务是如何实现的,我们将讨论MongoDB 4.2版发布后的其他令人兴奋的消息。
展开查看详情
1 . Transactions with MongoDB Shell MongoDB Transactions are here from version 4.0 -replica set! MongoDB Transactions are now possible with Shards also from version 4.2! Aayushi Mangal Support Engineer - Percona Global Services 1 © 2016 Percona
2 .Agenda ▪ Transactions ▪ Multi Document Transactions in MongoDB ▪ Lamport Logical clock ▪ Prerequisites ▪ Simple Atomic Transaction ▪ Commit Transactions (To save data changes) ▪ Abort Transactions (To discard data changes) ▪ Write conflicts ▪ What’s new ▪ Considerations ▪ Good References (Percona’s blogs on Session and Transaction) 2 © 2019 Percona
3 .Transactions • All data changes are saved if transaction got committed. • All data changes are discarded if any of the operation got failed in transaction. • Without a successful transaction no changes are visible to outside the transaction 3 © 2019 Percona
4 .Multi-Document Transactions in MongoDB • Prior to 4.0 MongoDB provides acid guarantees for single documents. • For Eg: If a single write operation include db.collection.updateMany(), changes of each document is atomic. • From version 4.0, these operations as a whole could be atomic. • Multi-document transactions can be used across multiple documents, collections or operations. • To maintain data integrity it follows all or nothing execution. 4 © 2019 Percona
5 .Lamport's Logical Clock Algorithm: 1) Counter is incremented by 1 before each next event of that process time=time+1 2) Each previous events sends a message that includes counter value along with message send(message+time) 5 © 2019 Percona
6 . Without Lamport Logical Clock Algorithm Primary Secondary1 Secondary2 Document D1 Read document D1, D1 D2 D3 D1 D2 D3 D1 D2 D3 updated but old value MongoDB replica set 6 © 2019 Percona
7 . With Lamport Logical Clock Algorithm Primary Secondary1 Secondary2 Document D1 Read request wait, gets D1 D2 D3 D1 D2 D3 D1 D2 D3 updated updated document. MongoDB replica set 7 © 2019 Percona
8 .Prerequisites ▪ Must be replica set > use db1 switched to db db1 > db.a.insert({name:"abc"}) WriteResult({ "nInserted" : 1 }) > s1 = db.getMongo().startSession() session { "id" : UUID("f6e87fde-0254-49cb-8b5c-9a052ebe80dc") } > s1.startTransaction() > s1.getDatabase("db1").a.find({name:"abc"}) Error: error: { "ok" : 0, "errmsg" : "Transaction numbers are only allowed on a replica set member or mongos", "code" : 20, "codeName" : "IllegalOperation" } 8 © 2019 Percona
9 .Prerequisites ▪ If Upgraded, from lower version, feature compatibility version must be 4.0 transRepl:PRIMARY> use db1 switched to db db1 transRepl:PRIMARY> s1=db.getMongo().startSession() session { "id" : UUID("2689aa65-342f-4664-8966-4fb862e8e17e") } transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").a.insert({name:"john"}) WriteCommandError({ "operationTime" : Timestamp(1561453446, 1), "ok" : 0, "errmsg" : "Transactions are only supported in featureCompatibilityVersion 4.0. See http://dochub.mongodb.org/core/4.0-feature-compatibility for more information.", "code" : 50773, "codeName" : "Location50773", "$clusterTime" : { "clusterTime" : Timestamp(1561453446, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } 9 } © 2019 Percona })
10 .Prerequisites ▪ If Upgraded, from lower version, feature compatibility version must be 4.0 transRepl:PRIMARY> db.adminCommand( { setFeatureCompatibilityVersion: '4.0' } ) transRepl:PRIMARY> db.adminCommand({getParameter:1, featureCompatibilityVersion:1}) { "featureCompatibilityVersion" : { "version" : “4.0” transRepl:PRIMARY> use db1 switched to db db1 transRepl:PRIMARY> s1=db.getMongo().startSession() session { "id" : UUID("a2a4aa8c-2f13-46a9-acd4-dc5dfc33bd06") } transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").a.insert({name:"john"}) WriteResult({ "nInserted" : 1 }) transRepl:PRIMARY> s1.commitTransaction() 10 © 2019 Percona
11 .Prerequisites ▪ Multi Document transaction cannot involve an insert operation for the non-existing collection. transRepl:PRIMARY> s1.getDatabase("db1").a.insert({name:"john"}) WriteCommandError({ "operationTime" : Timestamp(1561453726, 1), "ok" : 0, "errmsg" : "Cannot create namespace db1.a in multi-document transaction.", "code" : 263, "codeName" : "OperationNotSupportedInTransaction", "$clusterTime" : { "clusterTime" : Timestamp(1561453726, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }) 11 © 2019 Percona
12 .Prerequisites ▪ Transactions are only supported by wiredTiger storage Engine, why? transRepl:PRIMARY> db.serverStatus().storageEngine { "name" : "mmapv1", "supportsCommittedReads" : false, "supportsSnapshotReadConcern" : false, "readOnly" : false, "persistent" : true } transRepl:PRIMARY> s1 = db.getMongo().startSession() transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").col1.find({name:"abc"}) Error: error: { "operationTime" : Timestamp(1532248899, 1), "ok" : 0, "errmsg" : "Transaction numbers are only allowed on storage engines that support document- level locking", "code" : 20, "codeName" : "IllegalOperation", 12 © 2019 Percona
13 . Prerequisites ▪ Transactions are only supported by wiredTiger storage Engine, because: transRepl:PRIMARY> db.serverStatus().storageEngine { "name" : "mmapv1", "supportsCommittedReads" : false, "supportsSnapshotReadConcern" : false, "readOnly" : false, "persistent" : true } transRepl:PRIMARY> s1 = db.getMongo().startSession() transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").col1.find({name:"abc"}) Error: error: { "operationTime" : Timestamp(1532248899, 1), "ok" : 0, "errmsg" : "Transaction numbers are only allowed on storage engines that support document- level locking", "code" : 20, "codeName" : "IllegalOperation", 13 © 2019 Percona
14 .Transactions ▪ Simple Atomic Transaction transRepl:PRIMARY> s1=db.getMongo().startSession() session { "id" : UUID("392d5337-9aeb-4572-bef4-aff680a93a0c") } transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("transdb").col1.insert({"c":1}) WriteResult({ "nInserted" : 1 }) transRepl:PRIMARY> s1.commitTransaction() transRepl:PRIMARY> s1.endSession() 14 © 2019 Percona
15 .Transactions ▪ Commit Transactions to save data changes transRepl:PRIMARY> db.col1.find() { "_id" : ObjectId("5d11fd1c68ea949eeb55e23e"), "name" : "tom" } transRepl:PRIMARY> s1=db.getMongo().startSession() session { "id" : UUID("351a55cc-f8f5-413c-92e0-cb8fedaf9164") } transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").col1.insert({name:"jerry"}) WriteResult({ "nInserted" : 1 }) transRepl:PRIMARY> s1.commitTransaction() transRepl:PRIMARY> s1.endSession() transRepl:PRIMARY> db.col1.find() { "_id" : ObjectId("5d11fd1c68ea949eeb55e23e"), "name" : "tom" } { "_id" : ObjectId("5d12004068ea949eeb55e240"), "name" : "jerry" } //new document inserted 15 © 2019 Percona
16 .Transactions ▪ Abort Transactions to discard data changes transRepl:PRIMARY> db.col1.find() { "_id" : ObjectId("5d11fd1c68ea949eeb55e23e"), "name" : "tom" } transRepl:PRIMARY> s1=db.getMongo().startSession() session { "id" : UUID("7b3a0baa-75e2-41b1-bbba-649cabfeb7b3") } transRepl:PRIMARY> transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s1.getDatabase("col1").insert({name:"jerry"}) 2019-06-25T11:15:06.104+0000 E QUERY [js] TypeError: s1.getDatabase(...).insert is not a function : @(shell):1:1 transRepl:PRIMARY> s1.getDatabase("db1").col1.insert({name:"jerry"}) WriteResult({ "nInserted" : 1 }) transRepl:PRIMARY> transRepl:PRIMARY> transRepl:PRIMARY> s1.abortTransaction() transRepl:PRIMARY> s1.endSession() transRepl:PRIMARY> db.col1.find() { "_id" : ObjectId("5d11fd1c68ea949eeb55e23e"), "name" : "tom" } //no document inserted 16 © 2019 Percona
17 .WriteConflicts Transactions with write conflicts are aborted transRepl:PRIMARY> s1=db.getMongo().startSession() transRepl:PRIMARY> s2=db.getMongo().startSession() transRepl:PRIMARY> s1.startTransaction() transRepl:PRIMARY> s2.startTransaction() transRepl:PRIMARY> s1.getDatabase("db1").col1.update({name:"tom"},{$set:{name:"tom1"}},{multi:true}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 }) transRepl:PRIMARY> s2.getDatabase("db1").col1.update({name:"tom"},{$set:{name:"tom1"}},{multi:true}) WriteCommandError({ "errorLabels" : [ "TransientTransactionError" ], "operationTime" : Timestamp(1561461965, 1), "ok" : 0, "errmsg" : "WriteConflict", "code" : 112, "codeName" : "WriteConflict", "$clusterTime" : { "clusterTime" : Timestamp(1561461965, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } 17 © 2019 Percona
18 .What’s New? ▪ Transactions now possible with Sharded cluster. mongos> db.version() 4.2.0-rc1 mongos> use db1 switched to db db1 mongos> db.a.insert({name:"abc"}) WriteResult({ "nInserted" : 1 }) mongos> s1 = db.getMongo().startSession() session { "id" : UUID("5126ba83-439b-437d-8089-66396edfe08d") } mongos> s1.startTransaction() mongos> s1.getDatabase("db1").a.insert({name:"abc"}) WriteResult({ "nInserted" : 1 }) mongos> s1.commitTransaction() 18 © 2019 Percona
19 .Considerations ▪ Transaction size limit is 16MB transRepl:PRIMARY> s1.getDatabase("db1").col1.update({name:"abc"},{$set:{age:1}},{multi:true}) WriteCommandError({ "operationTime" : Timestamp(1532233021, 1), "ok" : 0, "errmsg" : "Total size of all transaction operations must be less than 16793600. Actual size is 16793722", "code" : 257, "codeName" : "TransactionTooLarge", "$clusterTime" : { "clusterTime" : Timestamp(1532233021, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }) 19 © 2019 Percona
20 .Considerations ▪ To use transactions for Replica set and shards drivers must be updated for MongoDB version 4.2 ▪ Read/Write is not possible for capped collections (from version 4.2) ▪ Read/Write operations are also prohibited for administrations databases like config, admin or local ▪ Non-CRUD operations like createUser, getParameter are restricted. 20 © 2019 Percona
21 .Considerations ▪ To use transactions for Replica set and shards drivers must be updated for MongoDB version 4.2 ▪ Read/Write is not possible for capped collections (from version 4.2) ▪ Read/Write operations are also prohibited for administrations databases like config, admin or local ▪ Non-CRUD operations like createUser, getParameter are restricted. 21 © 2019 Percona
22 .Good References ▪ MongoDB 3.6 session explained https://www.percona.com/blog/ 2017/12/08/mongodb-3-6-sessions-explained/ ▪ Your very first transaction With MongoDB 4.0 https:// www.percona.com/blog/2018/06/25/mongodb-transactions-your- very-first-transaction-with-mongodb-4-0/ ▪ MongoDB 4.0 ACID MultiDocument Transactions https:// www.percona.com/blog/2018/12/04/mongodb-4-0-using-acid-multi- document-transactions/ 22 © 2019 Percona
23 .Q and A 23 © 2018 Percona