In Spring Boot,@Transactional
It is a key annotation for declarative transaction management. It is based on Spring's AOP (System-Oriented Programming) implementation, which can simplify the management of database transactions.
1. Prerequisites
-
Dependency introduction: Make sure the project contains
spring-boot-starter-data-jpa
orspring-boot-starter-jdbc
-
Enable Transaction Management: Spring Boot automatically configures the transaction manager by default (such as
DataSourceTransactionManager
), no need to enable it manually.
2. Basic usage
1. Add annotations to the method
@Service public class UserService { @Autowired private UserRepository userRepository; @Transactional public void createUser(User user) { (user); // Other database operations } }
2. Add annotation on the class
@Service @Transactional public class UserService { // All public methods in the class apply transactions}
3. Core configuration parameters
1. Propagation behavior
Control the boundaries of transactions, default to。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void updateUser(User user) { // Always start new transactions}
Common options:
-
REQUIRED
(Default): Join if a transaction currently exists; otherwise, create a new one. -
REQUIRES_NEW
: Always create a new transaction and suspend the current transaction (if any) -
SUPPORTS
: Join if a transaction currently exists; otherwise, non-transaction runs -
NOT_SUPPORTED
: Non-transaction running, suspend the current transaction (if any) -
MANDATORY
: Must be called in the transaction, otherwise an exception will be thrown -
NEVER
: Must be called in non-transaction, otherwise an exception will be thrown
2. Isolation level
Control the isolation of transactions, default to(Use database default).
@Transactional(isolation = ) public void sensitiveOperation() { // Maximum isolation level}
3. Timeout
Transaction timeout (seconds), default -1 (using database default).
@Transactional(timeout = 30) public void longRunningProcess() { // Will roll back after more than 30 seconds}
4. ReadOnly mode
Optimized read-only operation, defaultfalse
。
@Transactional(readOnly = true) public List<User> findAllUsers() { return (); }
5. RollbackFor/noRollbackFor
Specify the type of exception that triggers the rollback:
@Transactional(rollbackFor = ) public void process() throws CustomException { // Roll back when throwing CustomException}
4. Key points to note
1. Method Visibility
Must bepublic
: Due to Spring AOP implementation mechanism, non-public methods@Transactional
invalid
2. Self-call problem
When methods in the same class are called each other, the transaction will not take effect (bypass the proxy object)
// Error examplepublic void methodA() { methodB(); // The transaction does not take effect} @Transactional public void methodB() { ... }
3. Exception handling
- Default rollback condition: throw
RuntimeException
orError
- Checked Exception will not trigger rollback by default
// Handle check-type exceptions@Transactional(rollbackFor = ) public void fileOperation() throws IOException { // ... }
4. Multi-data source transactions
Multiple transaction managers need to be configured and passed@Transactional(value = "specificTransactionManager")
Specify
5. Debugging skills
Enable debug logging:
=TRACE =DEBUG
Check the proxy object:
(().getName()); // The output should be a proxy class:.$ProxyXX or ...$$EnhancerBySpringCGLIB$$...
6. Best Practices
- Service layer usage: Use transactions in the Service layer instead of the Controller layer
- Keep short transactions: Avoid time-consuming operations such as remote calls, file IO, etc. in transactions
-
Precise rollback rules: Clearly specified
rollbackFor
Instead of relying on default behavior - Use in combination with JPA:
@Transactional public void updateUserEmail(Long userId, String email) { User user = (userId).orElseThrow(); (email); // Automatic dirty checking, update when transaction commits}
7. Complete example
@Service public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private InventoryService inventoryService; @Transactional( propagation = , isolation = Isolation.READ_COMMITTED, timeout = 30, rollbackFor = {, } ) public void placeOrder(Order order) { (()); // InsufficientStockException may be thrown (order); processPayment(order); // PaymentFailedException may be thrown } private void processPayment(Order order) { // Payment logic } }
8. Suitable for relational databases
@Transactional
The use of the database layer is directly related to the database layer, but its transaction management mechanism is based on database transactions. If the Service layer method uses Elasticsearch client read and write Elasticsearch, then@Transactional
behavior will be affected.
1.@Transactional
Scope of application
-
@Transactional
It is a transaction management mechanism provided by Spring, mainly used for managementDatabase transactions。 - It depends on the underlying transaction manager (e.g.
DataSourceTransactionManager
), and these transaction managers usually interact with relational databases (such as MySQL, PostgreSQL).
Database transactions:@Transactional
It ensures atomicity, consistency, isolation and persistence (ACID) of database operations.Non-database operations: For non-database operations (such as Elasticsearch, Redis, file system, etc.),@Transactional
It cannot directly manage its transactions.
and@Transactional
The relationship
Elasticsearch is a distributed search engine that does not support transactions (ACIDs) in the traditional sense. therefore,@Transactional
There is no direct transaction management capability for Elasticsearch operations.
(1) Scenario Analysis
Suppose our Service method operates both the database and Elasticsearch:
@Service public class UserService { @Autowired private UserRepository userRepository; // Database operation @Autowired private ElasticsearchClient elasticsearchClient; // Elasticsearch operation @Transactional public void createUser(User user) { // Operate the database (user); // Operation Elasticsearch IndexRequest request = new IndexRequest("users") .id(().toString()) .source("name", (), "email", ()); (request, ); } }
(2) Possible problems
- Database transactions rollback, Elasticsearch operations do not rollback:
- If (user) succeeds, but subsequent Elasticsearch operations fail, the database transaction will roll back (because @Transactional takes effect), but the data of Elasticsearch has been written and cannot be rolled back.
- Database transaction commits, Elasticsearch operation fails:
- If the database operation is successful, but the Elasticsearch operation fails, the database transaction has been committed, and the Elasticsearch data is not updated, resulting in inconsistent data.
3. How to solve the transaction consistency problem between Elasticsearch and database
Since Elasticsearch does not support transactions, other mechanisms need to be adopted to ensure data consistency.
(1) Manual compensation mechanism When the Elasticsearch operation fails, manually roll back the database operation.
Example:
@Transactional public void createUser(User user) { try { (user); // Database operation IndexRequest request = new IndexRequest("users") .id(().toString()) .source("name", (), "email", ()); (request, ); // Elasticsearch operation } catch (Exception e) { // Elasticsearch operation failed, manually roll back the database ().setRollbackOnly(); throw e; } }
(2) Message queue (final consistency)
- Asynchronize Elasticsearch operations and achieve final consistency through message queues (such as Kafka, RabbitMQ).
- Example:
After the database operation is completed, a message is sent to the queue.
The consumer reads messages from the queue and updates Elasticsearch.
(3) Two-stage submission (2PC)
- Use a distributed transaction manager such as Seata to implement distributed transactions for databases and Elasticsearch.
- This method is more complex and is usually not recommended for Elasticsearch.
(4) Local message table
- Create a message table in the database to record the data that needs to be synchronized to Elasticsearch.
- Synchronize data to Elasticsearch through a timing task or event listener.
Summarize
-
@Transactional
Only valid for database transactions: It cannot manage transactions that are non-relational data stores such as Elasticsearch. -
Consistency between Elasticsearch operations and database transactions: It needs to be achieved through compensation mechanisms, message queues, etc.
- Design suggestions: Try to avoid mixing database and Elasticsearch operations in the same transaction.
- Use asynchronous or final consistency schemes to ensure data consistency.
If you have more specific business scenarios, you can further discuss how to design a solution!
This is the end of this article about using Spring boot @Transactional for transaction management. For more related Spring boot @Transactional transaction management content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!