1. Spring's transaction mechanism
All data access technologies have transaction processing mechanisms, which provide APIs to enable transactions, commit transactions to complete data operations, or roll back data when an error occurs.
Spring's transaction mechanism uses a unified mechanism to handle transactions of different data access technologies. Spring's transaction mechanism provides a PlatformTransactionManager interface, and transactions of different data access technologies are implemented using different interfaces:
The code for defining a transaction manager in a program is as follows:
@Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; }2. Declarative transactions
Spring supports declarative transactions, that is, using annotations to select the method that needs to use transactions. It uses @Transactional annotation to indicate on the method that the method requires transaction support.
@Transactional public void saveSomething(Long id, String name) { //Database operation}It is important to note here that this @Transactional annotation comes from the org.springframework.transaction.annotation package, not javax.transaction.
Spring provides a @EnableTransactionManagement annotation to enable declarative transaction support on configuration classes. After using @EnableTransactionManagement, the Spring container will automatically scan the methods and classes annotated @Transactional. @EnableTransactionManagement is used as follows:
@Configuration @EnableTransactionManagement public class AppConfig { }3. Use @Transactional at the class level
@Transactional can not only annotate on methods, but also on classes. When annotating on a class, it means that all public methods of this class are transaction-activated. If the class level and method level use @Transactional annotation at the class level, the method level annotation will be overloaded using the class level.
4. Transaction support for Spring Data JPA
Spring Data JPA enables transaction support for all default methods, and the readOnly=true property is enabled by default for query transactions.
This can be seen from the source code SimpleJpaRepository that SimpleJpaRepository defines @Transactional (readOnly=true) at the class level, while the @Transactional property is rewritten in operations related to save and delete. At this time, the readOnly property is false, and the other query operations readOnly is still false.
5. Spring Boot's transaction support
1. Automatically configured transaction manager
When using JDBC as data access technology, SpringBoot defines the Bean of PlatformTransactionManager for us. See the definition in the org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration class:
@Bean @ConditionalOnMissingBean @ConditionalOnBean(DataSource.class) public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(this.dataSource); }When using JPA as data access technology, Spring Boot defines a bean for the PlatformTransactionManager implementation of JpaTransactionManager; see the definition in the org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.class class:
@Bean @ConditionalOnMissingBean(PlatformTransactionManager.class) public PlatformTransactionManager transactionManager() { return new JpaTransactionManager(); } 2. Automatically enable support for annotation transactions
Spring Boot is specially used to configure transactions as org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration. This configuration class depends on JpaBaseConfiguration and DataSourceTransactionManagerAutoConfiguration.
Support for declarative transactions is also enabled in the DataSourceTransactionManagerAutoConfiguration configuration, the code is as follows:
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class) @Configuration @EnableTransactionManagement protected static class TransactionManagementConfiguration { }So in Spring Boot, there is no need to display the @EnableTransactionManagement annotation enabled.
6. Example (Springboot)
1.pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
2.application.yml:
server: port: 5000 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8 username: root password: password jpa: hibernate: ddl-auto: update # The first simple table create is used to update show-sql: true
3. Entity class Staff:
@Entity public class Staff { @Id @GeneratedValue private Long id; private String name; private Integer age; private String address; public Staff() { super(); } public Staff(Long id, String name, Integer age, String address) { super(); this.id = id; this.name = name; this.age = age; this.address = address; } //Omit the get and set methods}4. Staff’s Repository:
public interface StaffRepository extends JpaRepository<Staff, Long> { }5. Service interface:
public interface StaffService { public Staff saveStaffWithRollBack(Staff staff);//Rollingback public Staff saveStaffWithoutRollBack(Staff staff);//Don't rollback}6. Service implementation:
@Service public class StaffServiceImpl implements StaffService { @Autowired StaffRepository staffRepository; //You can directly inject the bean of our RersonRepository. @Override //Use the rollbackFor attribute of @Transactional annotation to specify a specific exception, data will be rolled back. @Transactional(rollbackFor = {IllegalArgumentException.class}) public Staff saveStaffWithRollBack(Staff staff) { Staff s = staffRepository.save(staff); if (staff.getName().equals("Zhang San")) { throw new IllegalArgumentException("Zhang San already exists, rollback"); } return s; } @Override public Staff saveStaffWithoutRollBack(Staff staff) { Staff s = staffRepository.save(staff); if (staff.getName().equals("Zhang San")) { throw new IllegalArgumentException("Zhang San already exists, data does not roll back"); } return s; } }7.Controller:
@RestController @RequestMapping("/staff") public class StaffController { @Autowired StaffService staffService; //Test the rollback situation @RequestMapping("/rollback") public Staff rollback(Staff staff) { return staffService.saveStaffWithRollBack(staff); } //Test the rollback situation @RequestMapping("/notrollback") public Staff noRollBack(Staff staff) { return staffService.saveStaffWithoutRollBack(staff); } }8. Run the test:
(1) Rollback: http://localhost:5000/staff/rollback?name=Zhang San&age=18
Console:
database:
(2) No rollback: http://localhost:5000/staff/notrollback?name=Zhang San&age=18
Console:
database:
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.