GitHub 17K Star Java engineer into god’s path, not to learn about it!

GitHub 17K Star Java engineer into god’s road, really not to learn about it!

GitHub 17K Star Java engineer into god’s road, really really not to learn about it!

Transaction management is an indispensable part of system development. Spring provides a good transaction management mechanism, which is mainly divided into programmatic transaction and declarative transaction.

The basics of transactions, such as what a transaction is, database transactions, and the ACID, isolation level, propagation mechanism, behavior of Spring transactions, are not covered in detail in this article. By default, we all have a certain understanding.

In this article, I will briefly explain what declarative and programmatic transactions are and why I don’t recommend declarative transactions.

Programmatic transaction

Based on the underlying API, such as PlatformTransactionManager, TransactionDefinition and TransactionTemplate core interface, developers can programmatically for transaction management.

The programmatic transaction mode needs to be managed manually by the developer in the code to start, commit, roll back and so on.

public void test() { TransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); Try {/ / / transactions/transaction commit transactionManager.com MIT (status); } the catch (DataAccessException e) {/ / transaction commit transactionManager. Rollback (status); throw e; }}Copy the code

As in the above code, developers can control transactions themselves through the API.

Declarative transaction

The declarative transaction management approach allows transactions to be managed with the help of developer configurations without relying on the underlying API to be hard-coded. Developers can manage transactions using only annotations or configuration-based XML.

@transactional public void test() {Transactional public void test() {Copy the code

As above, use @transactional to add transaction control to the test method.

Of course, the above code is just a simplification and requires some configuration to use transactions. I won’t elaborate on that here.

These two kinds of transactions, the grid has their own advantages and disadvantages, so, what are the suitable scenarios for each? Why would anyone reject declarative transactions?

Advantages of declarative transactions

From the above example, we can easily see that declarative transactions help us to save a lot of code, it will automatically help us to open, commit and roll back transactions and other operations, freeing programmers from transaction management.

** Declarative transaction management is implemented using AOP, essentially intercepting target methods before and after execution. ** Adds or creates a transaction before the target method executes, and commits or rolls back the transaction after the execution method executes, depending on the actual situation.

In this way, the code is not intrusive; all you need to do is write the business logic inside the method.

But are declarative transactions really so good? Not really.

The granularity of declarative transactions

First, declarative transactions have the limitation that their minimum granularity applies to methods.

That is, if you want to add transactions to a block of code, you need to separate that block as a method.

However, because of this granularity, I do not recommend excessive use of declarative transactions.

First, because declarative transactions are annotated and can sometimes be configured, the problem is that the transaction can be ignored by the developer.

What’s wrong with transactions being ignored?

First, if the developer does not notice that a method is nested by a transaction, it is possible to add operations such as RPC remote calls, message sending, cache updates, and file writes to the method.

We know that there are two problems with these operations if they are wrapped in a transaction:

1. These operations cannot be rolled back by themselves, resulting in data inconsistencies. Maybe the RPC call succeeds but the local transaction is rolled back, but the PRC call cannot be rolled back.

2. Having a remote call in a transaction elongates the entire transaction. This will cause the database connection for this transaction to remain occupied, and if there are too many such operations, the database connection pool will be exhausted.

In some cases, someone may inadvertently perform some memory operations, such as operations, even if they are not performed remotely in a transaction. Or, if you encounter a situation where there are separate libraries and separate tables, you may inadvertently perform cross-library operations.

But with programmatic transactions, the business code will clearly see where the transaction is started, where it is committed, and when it is rolled back. When someone changes the code, it forces them to consider whether the code they want to add should be inside a method transaction.

Some people might say, well, you already have declarative transactions, but the person who wrote the code didn’t notice, and who can blame that?

Having said that, we still hope to reduce the probability of these problems through some mechanism or regulation.

For example, you are advised to use programmatic transactions rather than declarative transactions. Because, over the years that the author has worked, there have been more than one breakdowns caused by developers not noticing declarative transactions.

Because sometimes declarative transactions really aren’t obvious.

Declarative transactions are vulnerable to failure if not used correctly

In addition to the granularity of transactions, the problem with declarative transactions is that while they seem to simplify a lot of code, they can easily fail if they are not used correctly.

Declarative transactions can fail in the following scenarios:

Error Propagation @transactional error propagation @transactional error propagation @transactional error propagation @transactional error propagation @transactional error propagation The Transactional database engine does not support transactions. The Transactional database engine does not support transactions

Many of these problems can be avoided by using programmatic transactions.

The problem of declaring transaction invalidation has occurred many times. I don’t know if you’ve encountered it, but I’ve actually encountered it

Because Spring’s transactions are AOP based, but in code, sometimes we have many facets, different facets may handle different things, and multiple facets may interact.

Before a project, I will find all of our Service layer transaction fails, there is no rollback after failed to perform a SQL, screening down only to find that, because a colleague has added a section, this section do a unified capture abnormal, leading to the cut surface of the transaction did not catch exceptions, cause the transaction cannot be rolled back.

This happened more than once, and it was not easy to find.

Many people will still say that, in the final analysis, it is their own ability is not good, do not understand the business thoroughly, who can blame the wrong.

But again, we can’t guarantee that everyone will be competent, and we can’t expect all developers to be error-free. What we can do is try to avoid or reduce the probability of these problems by means of mechanisms or regulations.

In fact, if you have a careful look at alibaba out of the Java development manual, in fact, you can find that many of the rules are not completely easy to understand, and some are stiff, but in fact, these specifications are summed up by the developers who climbed out of countless pits.

The use of @transactional is also mentioned in the protocol, though it’s not as clear as I am:

conclusion

Finally, I believe that many people do not necessarily agree with this article, many people will say: Spring officially recommends non-invasive declarative transactions, you have no right to BB.

To be honest, in my first few years on the job, I was also a big fan of declarative transactions. I felt clean and “elegant”. I feel that the brothers use programming to do unnecessary work and have no craftsman spirit.

But over time, after a couple of things happened online, we went back and realized that a lot of the time your own code was pretty elegant, and it was totally fine.

But, elegant at the same time also brought some side effects, you can not criticize me, because MY usage is really correct…

So, some things, or to know after the pain.

Of course, this article does not require you to completely avoid declarative transactions, but it does suggest that you consider the ideas in this article and make your own choices when using transactions in the future.