In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >
Share
Shulou(Shulou.com)05/31 Report--
This article introduces the relevant knowledge of "how to solve the problem that database transactions did not take effect". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Spring declarative transaction provides convenient transaction configuration for Javaer. Coupled with Spring Boot automatic configuration, you can start the transactional configuration of the method instantly by adding @ Transactional annotation to the method.
But only add @ Transactional annotations to the method
You think that's enough?
If the transaction is not handled correctly, it generally does not cause the service to stop, and it is even more difficult to reproduce it in the test phase. However, as the system business becomes more and more complex, it will bring a large number of data inconsistencies, followed by a large number of online problems and then manual troubleshooting and maintenance data.
1 how does your Spring transaction take effect?
When you start a declarative transaction with @ Transactional, the soul asks: has the transaction taken effect?
Case
User table entity class
DAO layer
Query all data according to username
@ Repository public interface UserRepository extends JpaRepository {List findByName (String name);}
Service layer
UserService class
Responsible for business logic processing, including the following methods:
CreateUserWrong1 calls the private method:
CreateUserPrivate, annotated by @ Transactional. When the incoming user name contains test, an exception is thrown, causing the user's creation operation to fail, and the transaction is expected to be rolled back:
GetUserCount
Controller layer
Call the entry method createUserWrong1 in the UserService you just defined.
Test result
Even if the user name is illegal, the user can create it successfully. Refresh the browser and find illegal user registration many times.
2 @ Transactional how to make sure it works?
Unless there is a special configuration (such as implementing AOP using AspectJ static weaving), only @ Transactional defined on the public method will take effect.
Spring implements AOP by default through dynamic proxy, which enhances the target method, and the private method cannot be proxied to, and naturally, the transaction logic cannot be dynamically enhanced.
That's easy. Just change the createUserPrivate method to public.
Create another entry method createUserWrong2 in UserService to call the public method and try again:
Public int createUserWrong2 (String name) {try {this.createUserPublic (new UserEntity (name));} catch (Exception ex) {log.error ("create user failed because {}", ex.getMessage ());} return userRepository.findByName (name). Size ();} / marked @ Transactional's public method @ Transactional public void createUserPublic (UserEntity entity) {userRepository.save (entity) If (entity.getName (). Contains ("test") throw new RuntimeException ("invalid username!");}
The new createUserWrong2 method transaction also does not take effect.
The target method must be called externally through the proxied class
To call the enhanced method, it must be the object after calling the proxy.
Try to modify the UserService, inject a self, and then call the createUserPublic method marked with the @ Transactional annotation through the self instance. As you can see by setting breakpoints, self is a class enhanced by Spring through CGLIB.
CGLIB implements the proxy class through inheritance, and the private method is not visible in the subclass, so it naturally cannot be enhanced by transactions.
The this pointer represents the object itself, and Spring cannot be injected into this, so the access method through this must not be a proxy.
Change this to self and call the createUserRight method in Controller to verify that the transaction is in effect: illegal user registration operations can be rolled back.
Although injecting your own createUserPublic into the UserService can correctly implement the transaction, it doesn't conform to idiom. A more reasonable way to do this is to have Controller directly call the createUserPublic method of the previously defined UserService.
@ GetMapping ("right2") public int right2 (@ RequestParam ("name") String name) {try {userService.createUserPublic (new UserEntity (name));} catch (Exception ex) {log.error ("create user failed because {}", ex.getMessage ());} return userService.getUserCount (name);}
This self-call / self call / Controller call UserService
This self-calling
Unable to go to the Spring proxy class
The last two kinds
The UserService injected by the called Spring has the opportunity to dynamically enhance the createUserPublic method through the proxy call.
It is recommended that you open the relevant Debug log during development to learn the details of the Spring transaction implementation.
For example, to access JPA database, you can enable Debug log as follows:
Logging.level.org.springframework.orm.jpa=DEBUG
After enabling the log, compare the difference between this calls in UserService and createUserPublic calls through injected UserService Bean in Controller.
Obviously, because the this call is not proxied, the transaction does not take effect on the createUserPublic, only on the save of the Repository:
/ / call the createUserPublic of public through this in UserService [23 public 04bank 30.748] [http-nio-45678-exec-5] [DEBUG] [o.s.orm.jpa.JpaTransactionManager:370]-Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED ISOLATION_DEFAULT [DEBUG] [o.s.orm.jpa.JpaTransactionManager: 370]-Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED ISOLATION_DEFAULT / / call createUserPublic [10 UserService Bean 10 UserService Bean 47.750] [http-nio-45678-exec-6] [DEBUG] [o.s.orm.jpa.JpaTransactionManager: 370]-Creating new transaction with name [org.geekbang.time.commonmistakes.transaction.demo1.UserService.createUserPublic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT in Controller
This implementation is tedious to handle exceptions in Controller, so you might as well annotate createUserWrong2 directly with @ Transactional, and then call the method directly in Controller.
This is the end of the content of "how to solve the problem that the database transaction did not take effect". Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.