有人尝试过在.NetCore中使用事务吗?我尝试过,但无法正常工作。
我的设置:
我正在按照说明进行操作:https://docs.mongodb.com/manual/core/transactions/
问题是每次都会在数据库中创建新文档(如果我中止事务,如果我提交事务,...)
我也尝试过直接在数据库上使用事务,它们也可以工作,我也可以在NodeJS上进行尝试,它们也可以工作。也许驱动程序存在错误,我不知道我在做什么错。
代码:
using System;
using MongoDB.Bson;
using MongoDB.Driver;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var connString = "mongodb://user:password@localhost:27017";
var client = new MongoClient(connString);
using (var session = client.StartSession())
{
try
{
RunTransactionWithRetry(UpdateEmployeeInfo, client, session);
}
catch (Exception exception)
{
// do something with error
Console.WriteLine($"Non transient exception caught during transaction: ${exception.Message}.");
}
}
}
public static void RunTransactionWithRetry(Action<IMongoClient, IClientSessionHandle> txnFunc, IMongoClient client, IClientSessionHandle session)
{
while (true)
{
try
{
txnFunc(client, session); // performs transaction
break;
}
catch (MongoException exception)
{
// if transient error, retry the whole transaction
if (exception.HasErrorLabel("TransientTransactionError"))
{
Console.WriteLine("TransientTransactionError, retrying transaction.");
continue;
}
else
{
throw;
}
}
}
}
public static void CommitWithRetry(IClientSessionHandle session)
{
while (true)
{
try
{
session.CommitTransaction();
Console.WriteLine("Transaction committed.");
break;
}
catch (MongoException exception)
{
// can retry commit
if (exception.HasErrorLabel("UnknownTransactionCommitResult"))
{
Console.WriteLine("UnknwonTransactionCommiResult, retrying commit operation");
continue;
}
else
{
Console.WriteLine($"Error during commit: {exception.Message}.");
throw;
}
}
}
}
// updates two collections in a transaction
public static void UpdateEmployeeInfo(IMongoClient client, IClientSessionHandle session)
{
var employeesCollection = client.GetDatabase("testdatabase").GetCollection<BsonDocument>("employees");
var eventsCollection = client.GetDatabase("testdatabase").GetCollection<BsonDocument>("events");
session.StartTransaction(new TransactionOptions(
readConcern: ReadConcern.Snapshot,
writeConcern: WriteConcern.WMajority));
try
{
employeesCollection.UpdateOne(
Builders<BsonDocument>.Filter.Eq("employee", 3),
Builders<BsonDocument>.Update.Set("status", "Inactive"));
eventsCollection.InsertOne(
new BsonDocument
{
{ "employee", 3 },
{ "status", new BsonDocument { { "new", "Inactive" }, { "old", "Active" } } }
});
}
catch (Exception exception)
{
Console.WriteLine($"Caught exception during transaction, aborting: {exception.Message}.");
session.AbortTransaction();
throw;
}
//I WANT TO ABORT TRANSACTION - BUT THE RECORD "employee:3...." IS STILL IN DATABASE "events"
session.AbortTransaction();
}
public static void UpdateEmployeeInfoWithTransactionRetry(IMongoClient client)
{
// start a session
using (var session = client.StartSession())
{
try
{
RunTransactionWithRetry(UpdateEmployeeInfo, client, session);
}
catch (Exception exception)
{
// do something with error
Console.WriteLine($"Non transient exception caught during transaction: ${exception.Message}.");
}
}
}
}
}
答案 0 :(得分:3)
您需要将session
传递到操作中,以将其包括在交易会话中。即InsertOne方法接受IClientSessionHandle作为第一个参数。
否则,这些操作将在会话之外作为单独的操作进行操作。因此,中止实际上不会中止它们。
修改示例:
var database = client.GetDatabase("testdatabase");
var employeesCollection = database.GetCollection<BsonDocument>("employees");
var eventsCollection = database.GetCollection<BsonDocument>("events");
session.StartTransaction(new TransactionOptions(
readConcern: ReadConcern.Snapshot,
writeConcern: WriteConcern.WMajority));
try
{
employeesCollection.UpdateOne(
session,
Builders<BsonDocument>.Filter.Eq("employee", 3),
Builders<BsonDocument>.Update.Set("status", "Inactive"));
eventsCollection.InsertOne(
session,
new BsonDocument
{
{ "employee", 3 },
{ "status", new BsonDocument { { "new", "Inactive" }, { "old", "Active" } } }
});
}
catch (Exception exception)
{
Console.WriteLine($"Caught exception during transaction, aborting: {exception.Message}.");
session.AbortTransaction();
throw;
}
// OR session.CommitTransaction();
session.AbortTransaction();
上面的示例是使用MongoDB .Net driver v2.7和MongoDB 4.0编写的。
请注意,MongoDB Multi-Document Transactions要求集合名称空间存在。