当前位置:网站首页>New programmers optimize a line of code on Monday and are discouraged on Wednesday?
New programmers optimize a line of code on Monday and are discouraged on Wednesday?
2022-06-21 09:43:00 【Programmer Xiaohui】

This article is written by silent Wang Er (id:cmower) Authorized reprint
If you reprint, please contact the official account.
This Monday , A new colleague of the company , I did very well in the interview , All kinds of questions were answered fluently , The boss and I are very happy .
Such an excellent person , Never let him waste a minute , So soon , I sent him the requirements document 、 Source code , Let him familiarize himself with the business and development process locally .
It didn't work out , On Wednesday, let's review I found the problem when I was writing the code , The new colleague directly changed the original @Transactional Optimization is like this :
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)Just because of this line of code , Boss ( At that time, he was also a good player in the first-line Internet factory ) Got mad on the spot , This new colleague will soon be persuaded to leave , I'll make it right away , After all, the person you interview , Don't look at the Buddha's face , Is that so? ? So the boss promised me to try it for another month .
After the meeting , I hurriedly asked my new colleague to review the affairs , Here is his own summary , Still very detailed , Share it to give you a little reference and inspiration . I believe you will understand why you can't optimize it like this @Transactional Note the , It's just painting the lily and using it indiscriminately .
About affairs
A transaction is logically a set of operations , Or execute , Or not to carry out . Mainly for databases , for instance MySQL.
Just remember that , It's easy to understand things . stay Java in , We usually deal with multiple events in the business , For example, programming meow has a way to save articles , In addition to saving the article itself , Also save the tag corresponding to the article , Labels and articles are not in the same table , But will pass in the article table (posts) Save tag primary key (tag_id) To associate label tables (tags):
public void savePosts(PostsParam postsParam) {
// Save the article
save(posts);
// Handle labels
insertOrUpdateTag(postsParam, posts);
}Then you need to start the transaction , Ensure that the data in the article table and the label table are kept in sync , Or both , Either not .
Otherwise, it may cause , The article was saved successfully , But the label save failed , Or the article failed to save , Label saved successfully —— None of these scenarios met our expectations .
To ensure that transactions are correct and reliable , When the database is being written or updated , You have to show ACID Of 4 There are two important characteristics :
Atomicity (Atomicity): All operations in a transaction , Or it's all done , Or not at all , It doesn't end in the middle . An error occurred during the execution of the transaction , Will be rolled back (Rollback) Status to the beginning of the transaction , It's like this transaction has never been executed .
Uniformity (Consistency): Before and after transaction start , The integrity of the database is not compromised .
The transaction isolation (Isolation): The database allows multiple concurrent transactions to read, write and modify its data at the same time , Isolation can prevent data inconsistency caused by cross execution when multiple transactions are executed concurrently .
persistence (Durability): After transaction ends , Changes to data are permanent , Even if the system fails, it will not be lost .
among , Transaction isolation is divided into 4 There are two different levels , Include :
Uncommitted read (Read uncommitted), Lowest isolation level , allow “ Dirty reading ”(dirty reads), Transactions can see other transactions “ Not yet submitted ” Modification of . If another transaction rolls back , So the data read by the current transaction is dirty data .
Submit to read (read committed), A transaction may encounter a non repeatable read (Non Repeatable Read) The problem of . Nonrepeatable reading means , In a business , Read the same data multiple times , Before the end of the business , If another transaction happens to modify this data , that , In the first transaction , The data read twice may be inconsistent .
Repeatable (repeatable read), A transaction may encounter unreal reading (Phantom Read) The problem of . Unreal reading means , In a transaction , The first time to query a record , Found no , however , When trying to update this nonexistent record , To succeed , also , Read the same record again , It magically appears .
Serialization (Serializable), The strictest level of isolation , All transactions are executed in order , therefore , Dirty reading 、 It can't be read repeatedly 、 Unreal reading doesn't show up . although Serializable Transactions at the isolation level have the highest security , however , Because the transaction is serial execution , So the efficiency will be greatly reduced , The performance of the application will degrade dramatically . If there is no particularly important situation , I don't usually use Serializable Isolation level .
What needs special attention is : Whether the transaction can take effect , Depends on whether the database engine supports transactions ,MySQL Of InnoDB The engine supports transactions , but MyISAM I don't support .
About Spring Support for transactions
Spring Two transaction modes are supported , They are programmatic transactions and declarative transactions , The latter is most common , Usually only one is required @Transactional Just like the ( Code intrusion is minimized ), Just like this. :
@Transactional
public void savePosts(PostsParam postsParam) {
// Save the article
save(posts);
// Handle labels
insertOrUpdateTag(postsParam, posts);
}1) Programming transactions
Programming a transaction means embedding the transaction management code into the business code , To control transaction commit and rollback .
Do you like , Use TransactionTemplate To manage things :
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
// .... Business code
} catch (Exception e){
// Roll back
transactionStatus.setRollbackOnly();
}
}
});
}Again for instance , Use TransactionManager To manage things :
@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// .... Business code
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}In terms of programmatic transaction management ,Spring More recommended TransactionTemplate.
In programmatic transactions , Additional transaction management code must be included in each business operation , As a result, the code looks very bloated , But understanding Spring Our transaction management model is very helpful .
2) Declarative transactions
Declarative transactions separate transaction management code from business methods , Implement transaction management declaratively , For developers , Declarative transactions are obviously easier to use than programmatic transactions 、 Better to use .
Yes, of course , To realize the separation of transaction management and business code , You have to use Spring One of the most critical and core technologies ,AOP, Its essence is to intercept before and after the method , Then create or join a transaction before the target method starts , After the target method is executed, submit or roll back according to the execution status .
Declarative transactions are better than programmatic transactions , But there are also shortcomings , The granularity of declarative transaction management is method level , Programming transactions can be accurate to the code block level .
Transaction management model
Spring The core of transaction management is abstracted as a transaction manager (TransactionManager), Its source code has only a simple interface definition , Belongs to a tag interface :
public interface TransactionManager {
}This interface has two sub interfaces , They are programmatic transaction interfaces ReactiveTransactionManager And declarative transaction interface PlatformTransactionManager. Let's focus on PlatformTransactionManager, This interface defines 3 Interface methods :
interface PlatformTransactionManager extends TransactionManager{
// Get the transaction status according to the transaction definition
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
// Commit transaction
void commit(TransactionStatus status) throws TransactionException;
// Transaction rollback
void rollback(TransactionStatus status) throws TransactionException;
}adopt PlatformTransactionManager This interface ,Spring For various platforms such as JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager) The corresponding transaction manager is provided , But the specific implementation is the business of each platform .
Parameters TransactionDefinition and @Transactional Annotations correspond to , for instance @Transactional The transaction propagation behavior defined in the annotation 、 Isolation level 、 Transaction timeout 、 Whether the transaction is read-only , stay TransactionDefinition Can be found .
Return type TransactionStatus It is mainly used to store some states and data of the current transaction , For example, transaction resources (connection)、 Rollback status, etc .
TransactionDefinition.java:
public interface TransactionDefinition {
// The spread of transactions
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
}
// The isolation level of the transaction
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
}
// Transaction timeout
default int getTimeout() {
return TIMEOUT_DEFAULT;
}
// Whether the transaction is read-only
default boolean isReadOnly() {
return false;
}
}Transactional.java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
}@Transactional In the annotations propagation Corresponding TransactionDefinition Medium getPropagationBehavior, The default value is
Propagation.REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED).@Transactional In the annotations isolation Corresponding TransactionDefinition Medium getIsolationLevel, The default value is
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT).@Transactional In the annotations timeout Corresponding TransactionDefinition Medium getTimeout, The default value is TransactionDefinition.TIMEOUT_DEFAULT.
@Transactional In the annotations readOnly Corresponding TransactionDefinition Medium isReadOnly, The default value is false.
Speaking of this , Let's elaborate on Spring The spread of transactions 、 The isolation level of the transaction 、 Transaction timeout 、 Read only attribute of transaction , And rollback rules for transactions .
Transaction propagation behavior
When a transaction method is called by another transaction method , You must specify how transactions should propagate , for example , Method may continue to execute in the current transaction , You can also start a new transaction , Execute in your own business .
The propagation of declarative transactions can be done through @Transactional In the annotations propagation Attribute to define , for instance :
@Transactional(propagation = Propagation.REQUIRED)
public void savePosts(PostsParam postsParam) {
}TransactionDefinition A total definition of 7 Business communication behavior :
01、PROPAGATION_REQUIRED
This is also @Transactional Default transaction propagation behavior , This means that if a transaction currently exists , Then join the transaction ; If there is no current transaction , Create a new transaction . More precisely, it means :
If the external method does not open the transaction ,Propagation.REQUIRED Decorated internal methods open their own transactions , And the open transactions are independent of each other , Mutual interference .
If the external method starts a transaction and is Propagation.REQUIRED Words , all Propagation.REQUIRED Decorated internal methods and external methods belong to the same transaction , Just one method to roll back , The entire transaction needs to be rolled back .
Class A {
@Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
public void aMethod {
//do something
B b = new B();
b.bMethod();
}
}
Class B {
@Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
public void bMethod {
//do something
}
}This communication behavior is best understood ,aMethod Called bMethod, As long as one of the methods is rolled back , Roll back entire transaction .
02、PROPAGATION_REQUIRES_NEW
Create a new transaction , If there are currently transactions , Suspend the current transaction . That is to say, whether the external method opens the transaction or not ,Propagation.REQUIRES_NEW Decorated internal methods will open their own transactions , And the open transaction is independent of the external transaction , Mutual interference .
Class A {
@Transactional(propagation=Propagation.PROPAGATION_REQUIRED)
public void aMethod {
//do something
B b = new B();
b.bMethod();
}
}
Class B {
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void bMethod {
//do something
}
}If aMethod() An unexpected rollback occurred ,bMethod() It doesn't roll back , because bMethod() Open up a separate business . however , If bMethod() If an uncapped exception is thrown and the exception satisfies the transaction rollback rule ,aMethod() It also rolls back .
03、PROPAGATION_NESTED
If there are currently transactions , Execute within the current transaction ; otherwise , On execution and PROPAGATION_REQUIRED Similar operation .
04、PROPAGATION_MANDATORY
If there are currently transactions , Then join the transaction ; If there is no current transaction , Throw an exception .
05、PROPAGATION_SUPPORTS
If there are currently transactions , Then join the transaction ; If there is no current transaction , Continue to run in a non transactional manner .
06、PROPAGATION_NOT_SUPPORTED
Run in a non transactional manner , If there are currently transactions , Suspend the current transaction .
07、PROPAGATION_NEVER
Run in a non transactional manner , If there are currently transactions , Throw an exception .
3、4、5、6、7 this 5 Three transaction propagation methods are not commonly used , Understanding can .
Transaction isolation level
We have already known the transaction isolation level of the database , Then understand Spring The level of transaction isolation is much easier .
TransactionDefinition That's a total definition 5 Transaction isolation level :
ISOLATION_DEFAULT, Use the database's default isolation level ,MySql The default is REPEATABLE_READ, That's repeatable .
ISOLATION_READ_UNCOMMITTED, Lowest isolation level , There may be dirty reading 、 Unreal or unrepeatable .
ISOLATION_READ_COMMITTED, Allow reading data committed by concurrent transactions , It can prevent dirty reading , But unreal reading and unrepeatable reading can still happen .
ISOLATION_REPEATABLE_READ, Multiple reads of the same field are consistent , Unless the data is modified by its own transaction , Can prevent dirty and unrepeatable read , But phantom reading can still happen .
ISOLATION_SERIALIZABLE, Highest isolation level , Although it can prevent dirty reading 、 Unreal and unrepeatable reading , But it will seriously affect the program performance .
Usually , We use the default isolation level ISOLATION_DEFAULT That's all right. , That is, it is left to the database to decide , Can pass SELECT @@transaction_isolation; Order to see MySql The default isolation level of , The result is REPEATABLE-READ, That's repeatable .

Transaction timeout
Transaction Timeout , That is, the maximum time allowed for a transaction to be executed , If it has not been completed within the timeout period , Automatically rollback .
If the execution time of a transaction is extraordinarily long , Because the transaction involves locking the database , This will cause long-running transactions to consume database resources .
Read only attribute of transaction
If a transaction only reads from the database , Then the database can take advantage of the read-only attribute of the transaction , Take optimization measures , It is applicable to multiple database query operations .
Why should transaction support be enabled for a query operation ?
This is because MySql(innodb) Each connection is enabled by default autocommit Pattern , In this mode , Every one sent to MySql Server's SQL Statements are processed in a separate transaction , After execution, the transaction will be committed automatically .
So if we add @Transactional annotation , So all of this method SQL Will be put in one transaction . otherwise , Every one of them SQL Will start a transaction separately , The data is modified by other transactions , Will read in real time .
In some cases , When multiple query statements are executed at once , When data consistency needs to be ensured , You need to enable transaction support . Otherwise, the previous one SQL After query , Data changed by other users , So next SQL Queries may have inconsistent states .
Rollback strategy of transaction
By default , Transaction exception only at run time (Runtime Exception) Roll back on , as well as Error, A check exception occurred (checked exception, Active capture processing or upward throwing is required ) Do not roll back .
https://tobebetterjavaer.com/exception/gailan.html
If you want to rollback a specific exception type , You can set it like this :
@Transactional(rollbackFor= MyException.class)About Spring Boot Support for transactions
before , We need to pass XML To configure Spring To host transactions , With Spring Boot after , Everything becomes easier , Just add transaction annotations in the business layer (@Transactional) You can quickly start a transaction .
in other words , We just need to focus on @Transactional Just annotate it .
@Transactional The scope of action of
Class , Indicates all... In the class public Methods enable transactions
On the way , The most commonly used one
On the interface , It is not recommended to use
@Transactional Common configuration parameters
although @Transactional Many attributes are defined in the annotation source code , But most of the time , I use the default configuration , Yes, of course , If you need to customize , It has been explained above .
@Transactional A summary of the precautions in the use of
1) To be in public Methodically used , stay AbstractFallbackTransactionAttributeSource Class computeTransactionAttribute There is a judgment in the method , If the target method is not public, be TransactionAttribute return null, That is, transactions are not supported .
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}2) Avoid calling in the same class @Transactional Method of annotation , This will cause the transaction to fail .
Test whether the transaction is effective
Before the test , Let's put the Spring Boot Default log level info Adjusted for debug, stay application.yml In file modify :
logging:
level:
org:
hibernate: debug
springframework:
web: debugthen , Look at the data found before modification :

Open up . Add a... To the controller update Interface , Ready to modify the data , I plan to change the dogleg of silent King II into that of silent King II :
@RequestMapping("/update")
public String update(Model model) {
User user = userService.findById(2);
user.setName(" The dog leg of silent King II ");
userService.update(user);
return "update";
} stay Service Add... To the method in @Transactional Annotate and throw a runtime exception :
@Override
@Transactional
public void update(User user) {
userRepository.save(user);
throw new RuntimeException(" ah , There are monsters !");
}As we expected , When executed save After saving data , Because there's an anomaly , So the transaction should be rolled back . So the data will not be modified .
Enter... In the browser http://localhost:8080/user/update To test , Pay attention to the log , It can be confirmed that the transaction works .

When we get rid of things , Also throw an exception :
@Override
public void update(User user) {
userRepository.save(user);
throw new RuntimeException(" ah , There are monsters !");
}Re execution , I found that although the program reported an error , But the data has been updated .

This also indirectly proves , our @Transactional Things work .
See this , Do you understand why the optimization of new colleagues is just adding to the icing on the cake / Let's use the eggs ?
Project source code
Programming meow :https://github.com/itwanger/coding-more
Source code of this project :https://github.com/itwanger/codingmore-learning
Reference source :
Wikipedia :https://zh.wikipedia.org/wiki/ACID
Wikipedia :https://zh.wikipedia.org/wiki/ Transaction isolation
Liao Xuefeng :https://www.liaoxuefeng.com/wiki/1177760294764384/1179611198786848
JavaGuide:https://juejin.cn/post/6844903608224333838
Xiaohui, the whole dish Engineer :https://aijishu.com/a/1060000000013284
unreality :https://segmentfault.com/a/1190000040130617
A sock :https://www.jianshu.com/p/380a9d980ca5
边栏推荐
- stm32mp1 Cortex M4开发篇13:扩展板按键外部中断
- equals 和 hashCode
- Common basic functions of R language: call the data editor with edit function to manually customize and edit the data object without changing the content of the original data object, and call the data
- It is said that this year gold three silver four has become gold one silver two.
- Clipboard learning records and pit encountered
- 118. summary of basic knowledge of typescript (data type, interface, abstract class, inheritance, attribute encapsulation, modifier)
- Unity中的地平面简介
- Use this for attributes in mapstate
- 【实战】STM32MP157开发教程之FreeRTOS系统篇6:FreeRTOS 列表和列表项
- 121. Redux detailed summary + effect drawing + Case
猜你喜欢

【实战】STM32MP157开发教程之FreeRTOS系统篇6:FreeRTOS 列表和列表项

The spring recruitment is also terrible. Ali asked at the beginning of the interview: how to design a high concurrency system? I just split

Request and response must know

stm32mp1 Cortex M4开发篇12:扩展板震动马达控制

基因型填充前的质控条件简介

Unity中的地平面简介

Job hopping is better than promotion

Classification of ram and ROM storage media

燎原之势 阿里云数据库“百城聚力”助中小企业数智化转型

Stm32mp1 cortex M4 development part 13: external interrupt of expansion board key
随机推荐
内部类
R language obtains help information of global, package and function: use the rsitesearch function to search the information of the specified package or function in the R community help manual and arch
【云原生 | Kubernetes篇】Kubernetes 配置(十五)
Clipboard learning records and pit encountered
Ccs7.3 how to erase only part of the flash sector when burning DSP on-chip flash (two projects of on-chip flash burning of a DSP chip)
The spingboot microservice is packaged into a docker image and connected to the database
如何做一个有趣的人
嵌入式远程岗位、兼职、接单、众包平台
Full stack development
TC软件详细设计文档(手机群控)
异常
程序员新人周一优化一行代码,周三被劝退?
121. Redux detailed summary + effect drawing + Case
Equals and hashcode
从零开始做网站11-博客开发
TC软件概要设计文档(手机群控)
113. summary of common usage of moment.js
Odd number of characters异常
Alibaba P6 employees came to a small company for an interview and asked for an annual salary increase of 500000 yuan. How dare you speak
Several ways to trigger link jump