1 - @EnableTransactionManagement & Configure TransactionManager
@EnableTransactionManagementenables Spring’s annotation-driven transaction management capability (e.g.@Transactional)- see:
TransactionManager
Code Example
@Configuration @EnableTransactionManagement // <-------------------------------- (1) public class MySpringConfig { @Bean public DataSource dataSource() { return new MysqlDataSource(); // <----------------------- (2) } @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); // (3) } }
@EnableTransactionManagementenables Spring’s annotation-driven transaction management capability (e.g.@Transactional)- create a database-specific or connection-pool specific
DataSourcehere (MySQL is being used for this example)- create
TransactionManager, which needs aDataSourceto be able to manage transactions (for in-depth understanding see otherPlatformTransactionManagerimplementations that Spring offers)
2 - Using @Transactional
public class UserService {
@Transactional
public Long registerUser(User user) {
// execute some SQL that e.g.
// inserts the user into the db and retrieves the autogenerated id
// userDao.save(user);
return id;
}
}
Armed with the knowledge from the JDBC transaction example, the @Transactional UserService code above translates (simplified) directly to this:
public class UserService {
public Long registerUser(User user) {
Connection connection = dataSource.getConnection();
try (connection) {
connection.setAutoCommit(false);
// execute some SQL that e.g.
// inserts the user into the db and retrieves the autogenerated id
// userDao.save(user);
connection.commit();
} catch (SQLException e) {
connection.rollback();
}
}
}
3 - @Transactional Attributes
Spring transaction provides support for following six attributes which determines the behavior of the transaction:
|
Attribute |
Default |
Description |
|---|---|---|
|
|
|
The name of If the bean name of the |
|
|
|
The transaction propagation level |
|
|
|
The transaction isolation level |
|
|
|
The transaction timeout value (in seconds) |
|
|
|
Is this transaction read-only? |
|
|
|
The |
|
|
|
The |
|
|
|
The |
|
|
|
The |
4 - @Transactional Class vs Method Level
@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// ...
}
}
5 - @Transactional Under the Covers (Session)
In Spring, there is a one-to-one correspondence between the business transaction demarcated by @Transactional, and the hibernate Session.
That is, when a business transaction is begun by invoking a @Transactional method, the hibernate session is created (a TransactionManager may delay the actual creation until the session is first used). Once that method completes, the business transaction is committed or rolled back, which closes the hibernate session.
@Transactional can start new transaction or can join existing transactional context based its propagation attribute value.
In @Transactional context, getCurrentSession() method creates new Session object if it does not exist or returns Session which is attached to current transaction. openSession() method always creates new session. @Transactional helps you to extend scope of Session.
Session is open first time when getCurrentSession() is executed and it is closed when transaction ends and it is flushed before transaction commits.
In Spring, If we use getCurrentSession() in non-transactional context we get an exception
6 - @Transactional Under the Covers (CGlib & JDK Proxies)
Let’s see proxies in action in this picture:
/java-platform/java/java---projects--and--code-examples/java---non-native-libraries/java---spring-family/java---spring-data/java---spring-data---transaction-management/java---spring---@enabletransactionmanagement--and--@transactional/spring-transaction.png)
As you can see from that diagram, the proxy has one job.
- Opening and closing database connections/transactions (the proxy delegates that work to a
TransactionManager) - And then delegating to the real
UserService - And other beans, like your
UserRestControllerwill never know that they are talking to a proxy, and not the real thing