Java Web Spring Boot中的@Transactional注解详解
目录
概念解释
@Transactional:在Spring框架中,@Transactional
注解用于声明式事务管理。通过在方法或类上添加@Transactional
注解,可以使得该方法或类中的所有方法在执行时都处于一个事务上下文中。事务管理可以确保数据操作的原子性、一致性、隔离性和持久性(ACID属性)。
事务的ACID属性:
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
- 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性(Durability):事务一旦提交,其结果就是永久性的,即使系统故障也不会丢失。
@Transactional的基本使用
1. 添加依赖
首先,确保在pom.xml
中添加Spring Boot的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 配置数据源
在application.properties
中配置数据源:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
3. 创建实体类
创建一个简单的实体类,例如User
:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters and setters
}
4. 创建Repository接口
创建一个JPA Repository接口:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
5. 创建Service类
在Service类中使用@Transactional
注解:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
}
@Transactional
public void createUsers(List<User> users) {
for (User user : users) {
userRepository.save(user);
}
}
}
6. 创建Controller类
创建一个Controller类来处理HTTP请求:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/users")
public void createUser(@RequestBody User user) {
userService.createUser(user);
}
@PostMapping("/users/batch")
public void createUsers(@RequestBody List<User> users) {
userService.createUsers(users);
}
}
@Transactional的属性
@Transactional
注解提供了多个属性,用于更细粒度地控制事务行为:
-
propagation:事务传播行为,默认值为
Propagation.REQUIRED
。REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。REQUIRES_NEW
:创建一个新事务,如果当前存在事务,则挂起当前事务。SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,则挂起当前事务。MANDATORY
:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。NEVER
:以非事务方式执行,如果当前存在事务,则抛出异常。NESTED
:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新事务。
-
isolation:事务隔离级别,默认值为
Isolation.DEFAULT
。DEFAULT
:使用底层数据库的默认隔离级别。READ_UNCOMMITTED
:读未提交,允许脏读、不可重复读和幻读。READ_COMMITTED
:读已提交,禁止脏读,允许不可重复读和幻读。REPEATABLE_READ
:可重复读,禁止脏读和不可重复读,允许幻读。SERIALIZABLE
:串行化,禁止脏读、不可重复读和幻读。
-
timeout:事务超时时间,默认值为
-1
,表示使用底层数据库的默认超时时间。 -
readOnly:是否为只读事务,默认值为
false
。 -
rollbackFor:指定哪些异常需要回滚事务。
-
noRollbackFor:指定哪些异常不需要回滚事务。
示例:使用@Transactional
的属性
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, timeout = 30, readOnly = false)
public void createUser(User user) {
userRepository.save(user);
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = {RuntimeException.class, IOException.class})
public void createUsers(List<User> users) {
for (User user : users) {
userRepository.save(user);
}
}
}
默认会触发事务回滚的异常类型
在Spring框架中,@Transactional
注解默认会对RuntimeException
及其子类和Error
及其子类进行回滚。这意味着,如果在事务方法中抛出了这些异常,事务将会回滚。
具体来说,以下是默认会触发事务回滚的异常类型:
-
RuntimeException及其子类:
NullPointerException
IllegalArgumentException
IndexOutOfBoundsException
ArithmeticException
ClassCastException
- 等等
-
Error及其子类:
OutOfMemoryError
StackOverflowError
NoClassDefFoundError
- 等等
示例
假设我们有一个简单的服务方法,它会抛出一个RuntimeException
:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
throw new RuntimeException("Something went wrong!");
}
}
在这个例子中,当createUser
方法抛出RuntimeException
时,事务将会回滚,之前保存的用户数据不会被提交到数据库。
自定义回滚规则
如果你希望对其他类型的异常也进行回滚,或者希望某些特定异常不触发回滚,可以使用@Transactional
注解的rollbackFor
和noRollbackFor
属性进行自定义。
示例:自定义回滚异常
假设我们希望对IOException
也进行回滚:
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(rollbackFor = {RuntimeException.class, IOException.class})
public void createUser(User user) throws IOException {
userRepository.save(user);
throw new IOException("Something went wrong!");
}
}
在这个例子中,当createUser
方法抛出IOException
时,事务将会回滚。
示例:指定不回滚的异常
假设我们希望某些特定的RuntimeException
不触发回滚:
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(noRollbackFor = {CustomRuntimeException.class})
public void createUser(User user) {
userRepository.save(user);
throw new CustomRuntimeException("This exception will not cause rollback!");
}
}
在这个例子中,当createUser
方法抛出CustomRuntimeException
时,事务不会回滚。