关于Spring中声明式事务的使用详解
什么是声明式事务?
在Spring中,事务是指一组需要保证数据完整性和一致性的数据库操作。 在进行事务处理时,必须保证多个操作的原子性,即所有操作都能够全部成功或全部失败。
Spring中的声明式事务是基于AOP实现的,通过对方法进行拦截,在方法执行前后加上事务的开始和结束语句,来实现事务的管理。这样即使开发人员忘记在方法中手动添加事务的开始和结束语句,也可以确保方法能够在事务环境中执行,保证数据的完整性和一致性。
如何使用声明式事务?
配置文件中的声明式事务
在Spring中,我们可以在配置文件中通过<tx:advice>
和<aop:config>
标签声明式定义事务。下面是一个示例:
<bean id="userService" class="com.example.UserService" />
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userServicePointcut" expression="execution(* com.example.UserService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointcut"/>
</aop:config>
上述代码中,我们首先声明了一个名为txManager
的事务管理器,以管理使用Spring声明式事务的数据源。然后我们使用<tx:attributes>
标签定义了事务传播机制、是否只读等Transaction Attributes信息,接着我们在<tx:advice>
标签中引入刚才声明的事务管理器,并且将之前定义好的<tx:attributes>
添加进去。最后使用<aop:config>
标签进行切面配置,并在<aop:pointcut>
标签中定义所需要拦截的方法,即com.example.UserService
中的所有方法。最后通过<aop:advisor>
标签将拦截器和切面关联起来。
在这个示例中,我们通过如上的配置,可以对UserService
中的所有公有方法进行事务管理。当我们调用save
、update
、delete
等写操作时,将会被Spring事务拦截并在方法执行前开启事务,在方法执行后进行事务提交或回滚。
使用注解的声明式事务
注解式事务是一种使用注解的方式声明事务的方式。相比于xml配置的方式,这种方式更加简洁明了。
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void save(User user) throws Exception {
userDao.save(user);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void update(User user) throws Exception {
userDao.update(user);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void delete(Long userId) throws Exception {
userDao.delete(userId);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS, readOnly = true)
public User findUserById(Long userId) throws Exception {
return userDao.findUserById(userId);
}
}
上述代码中我们在UserService类中对方法进行了注解式事务的声明,通过@Transactional
注解的propagation
属性来确定事务传播机制,readOnly
属性来指明方法是否为只读操作。我们还可以通过rollbackFor
和noRollbackFor
属性来指明哪些异常需要回滚事务,哪些异常不需要回滚事务。
实例演示
在本次演示中,我们将使用Spring、MySQL和SpringMVC实现一个简单的增删改查功能。具体的示例代码参见https://github.com/LZxiaozhi/spring-transaction-demo
。
步骤
- 创建SpringMVC项目。
- 引入相关依赖。
- 在配置文件中配置MySQL数据源。
- 创建DAO层和Service层。
- 在Controller层中进行测试。
代码示例
- 配置文件
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userServicePointcut" expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointcut"/>
</aop:config>
- Service层
@Service
public class UserService {
@Autowired
private UserDao userDao;
public List<User> findAll() {
return userDao.findAll();
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void save(User user) throws Exception {
userDao.add(user);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void update(User user) throws Exception {
userDao.update(user);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void delete(Long id) throws Exception {
userDao.delete(id);
}
}
- Controller层
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String index(Model model) {
List<User> userList = userService.findAll();
model.addAttribute("userList", userList);
return "index";
}
@GetMapping("/add")
public String add() {
return "add";
}
@PostMapping("/add")
public String save(User user) throws Exception {
userService.save(user);
return "redirect:/";
}
@GetMapping("/edit/{id}")
public String edit(@PathVariable Long id, Model model) throws Exception {
User user = userService.findById(id);
model.addAttribute("user", user);
return "edit";
}
@PostMapping("/edit/{id}")
public String update(@PathVariable Long id, User user) throws Exception {
user.setId(id);
userService.update(user);
return "redirect:/";
}
@GetMapping("/delete/{id}")
public String delete(@PathVariable Long id) throws Exception {
userService.delete(id);
return "redirect:/";
}
}
结论
在以上演示示例中,我们通过使用Spring中的声明式事务实现了数据的增删改查功能。
声明式事务的使用需要开发人员对AOP、事务传播机制等基本概念有一定的理解;在配置中需要注意propagation
和readOnly
等属性的值得合理配置;在实际应用中,我们可以通过注解和xml配置两种方式声明式的配置Spring事务。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:关于Spring中声明式事务的使用详解 - Python技术站