background story
In the 2.3 version, we made some adjustments to Api. Why do we make these adjustments? I’ll talk about this process.
I believe that all of you who are using CAP know that there is a Bug in 2.2 and previous versions that persists messages to the database in the case of transactions and if no transactions have been committed, then the CAP will start sending messages to the message queue, but one question askedThe problem is that if the next transaction fails to commit, then the message has actually been sent, and the consumer receives the message, corresponding to the GitHub issue.
This Bug is serious and not serious, but we always have to solve this problem. How can we solve this problem? Some students may say that it is not enough to change the sending message to the transaction after the completion of submission, but the CAP is unable to obtain the results of business-side transaction execution, because.NET does not have a mechanism like Spring Transaction that can easily be extended, so if you want to change to post-transaction commit, you must provide an API for the user to call manually to send. It seems easy to solve this problem.But I think it’s going to cost users an extra line of code, it’s going to cost them more to learn, it’s going to cost them more to understand what’s going on inside the framework, and it’s possible to forget to call or use it incorrectly.
In order for CAP users to write less about this line of code, I think about it for a couple of months and talk about the process.
Anyone who knows something about the underlying database-driven code probably knows that the database-driven encapsulation is particularly deadly, especially when dealing with transactions, classes are sealed and there’s little way to extend them. I’ve made some attempts to fail, and eventually I want to fork a piece of data.The library driver modified and released its own Nuget package, but the solution was eventually rejected because I was unwilling to use my own compiled database driver, and eventually the path was not working.
Another solution is that students who know something about Diagnostics might have thought of using this feature to track the results of transaction submissions and then do something about them. But what is the problem? At present, only SQL Server driver supports.Diagnostics, other MySql, PostgreSql do not support, what to do? It’s impossible to ignore those users who use MySql, PostgreSql, because we use MySql ourselves.
Lemon and I submitted PR (MySql PR, PostgreSql PR) support for diagnostics features to MySql and PostgreSql C# database projects, respectively, but because Microsoft didProblems with the design of the Diagnostics Source API have caused the community to resent the way the API works, and there are also principles in the guidance document that Microsoft does not follow in the SQL Client driver, so these two PR1There has been no merger. Interested people can also look at the discussion here, so they do not know when to wait.
Another reason is that since we need to dock the new MongoDB, MongoDB’s handling of transactions differs in APIs, and in order to provide a consistent user interface, some changes need to be made.
Above, we need to make adjustments to API, and we can’t remain stagnant. Let’s take a look at the changes made in version 2.3.
CAP 2.3″
1″ and removed the CAP middleware registry.
Now, you don’t need to use it anymore.app.UseCap()
Manually adding middleware, we will automatically register.
In previous versions of 2.3, CAP had to be registered in Startup Configure, and now we’ve automatically registered at startup, you don’t need to register manually.
public void Configure(IApplicationBuilder app)
{
app.UseCap(); //Removed, no manual registration is required.}
2″ and modified the key type of message table.
To adapt to the latest MonoDB and data table migration in some scenarios, we change the primary key Id of the message table from a self-growing int type to a long type generated by the snowflake algorithm, which can improve the performance of message processing and the complexity of logic to a certain extent.
Upgraded from version 2.2, we provide database migration scripts, you can see here to get the database migration scripts, and then execute in the database.
https://gist.github.com/yuleyule66/0e5ec7a5046dc58fcf89d51e4820c5cd
3″ and modified Publish Api.
We added a new one.ICapTransaction
Interface, used to control transaction processing, and also to handle situations where transaction processing interfaces are not tracked, and we encapsulate a series of extensions for developers to use, let’s take a look at the new Api
- MongoDB:
using (var session = _mongoClient.StartTransaction(_capBus, autoCommit: false))
{
var collection = _mongoClient.GetDatabase("test").GetCollection<BsonDocument>("test.collection");
collection.InsertOne(session, new BsonDocument { { "hello", "world" } });
_capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now);
session.CommitTransaction();
}
Thereconnection.StartTransaction
It is an extension method.This extension method returns.IClientSessionHandle
Interface,It represents the native transaction object of MongoDB, which we can use when we get it to do our own business code.
The reason for naming StartTransaction is that we want to follow the naming specification of MongoDB, which is easy for users to understand.
- SQLServer:
using (var connection = new SqlConnection(""))
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))
{
//your business code sample
connection.Execute("insert into test(name) values('test')", transaction);
_capBus.Publish("sample.rabbitmq.sqlserver", DateTime.Now);
transaction.Commit();
}
}
Thereconnection.BeginTransaction
It is an extension method.This extension method returns.IDbTransaction
Interface,It represents a native transaction object of the database that we can pass to Dapper or Ado. net while doing our own business code.
- MySql And PostgreSql:
using (var connection = new MySqlConnection(""))
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false))
{
//your business code sample
connection.Execute("insert into test(name) values('test')",transaction: (IDbTransaction)transaction.DbTransaction);
_capBus.Publish("sample.rabbitmq.mysql", DateTime.Now);
transaction.Commit();
}
}
Thereconnection.BeginTransaction
It is an extension method.This extension method returns.ICapTransaction
Interface,Interface packageDbTransaction
Property, which represents the native transaction object of the database, is passed to Dapper or Ado. net when we do our own business code.
4″, increased transaction automatic submission.
In some cases, in order to simplify the code, we do not want to manually invoke.transaction.Commit()
We hope that CAP can help you submit your business, so you can do it.connection.BeginTransaction
Pass parametersautoCommit
bytrue
You can.
Note that when using the transaction autocommit function, you need to send a message after your business logic has been executed, that is to say_capBus.Publish
This line of code needs to be put to the last execution. Example code:
using (var connection = new MySqlConnection(""))
{
using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))
{
//your business code sample
_capBus.Publish("sample.rabbitmq.mysql", DateTime.Now);
}
}
Pay attention to this.autoCommit: true
,And cancelled it.transaction.Commit()
5, increase support for MongoDB”
In micro-service applications, sometimes some of our services may be for performance or other reasons, using non-traditional relational databases, and some non-relational databases, such as MongoDB as the representative, use the most people, and then there is a need to hope to store data.Time also wants to ensure high consistency of data.
MongoDB ACID transactions are supported in versions 4.0 and above, which gives us reason to support MongoDB, and MongoDB support is PR provided by Keke students in the blog garden. Thank you again.
Some students may want to try, so let’s simply say, MongoDB support for ACID transactions is needed to cluster to use, so we need to build a cluster first, build a cluster article I have written, you can refer to this blog to build.
After the cluster is completed, it is in the Startup.cs file.ConfigureServices(IServiceCollection services)
It can be configured in the middle.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMongoClient>(new MongoClient("mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0"));
services.AddCap(x =>
{
x.UseMongoDB("mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0");
x.UseRabbitMQ("localhost");
x.UseDashboard();
});
}
Usage method:
Note: MongoDB can’t create databases and collections in a transaction, so if your cluster is empty after it’s created, you need to create the databases and collections separately, and you can simulate a record insert to create them automatically.
var mycollection = _client.GetDatabase("test").GetCollection<BsonDocument>("test.collection");
mycollection.InsertOne(new BsonDocument { { "test", "test" } });
Then?
[Route("~/without/transaction")]
public IActionResult WithoutTransaction()
{
_capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now);
return Ok();
}
[Route("~/transaction/not/autocommit")]
public IActionResult PublishNotAutoCommit()
{
//NOTE: before your test, your need to create database and collection at first
using (var session = _client.StartTransaction(_capBus, autoCommit: true))
{
var collection = _client.GetDatabase("test").GetCollection<BsonDocument>("test.collection");
collection.InsertOne(session, new BsonDocument { { "hello", "world" } });
_capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now);
}
return Ok();
}