spring-boot事务也就是使用spring事务,业务执行过程中出现异常事务能够自动回滚,避免数据库出现脏数据。
1)Mybatis(UserMapper)加入insert方法
insert into user(id, name) values (#{id}, #{name})
@Repository
public interface UserMapper {
@Select("select name from user where id = #{id}")
String findNameById(@Param("id") String id);
User findUserById(@Param("id") String id);
int insert(User user);
}
2) 编写UserService,加入insert方法
@Service
public class UserService {
@Autowired
private UserMapper userDao;
public int insert(User user){
int i= userDao.insert(user);
if(i==1){
throw new RuntimeException("error");
}
return i;
}
}
3)编写UserController,提供增加用户的接口
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "addUser")
public Object addUser(@RequestParam(value = "id")String id, @RequestParam(value = "name")String name){
User user=new User();
user.setId(id);
user.setName(name);
return userService.insert(user);
}
}
4. 测试
调用http://127.0.0.1:8081/addUser?id=3&name=kevin3后,返回异常,但数据库却增加了相应的user记录,这显然不是我们想要的,所以需要加入事务。
1)在configuration上加@EnableTransactionManagement开启事务,springboot默认开启事务不需要手动加。
2)在service类(方法)上加入@Transactional可开启事务,注意加在类上只针对public的方法有效
package com.kevin.springbootstudy.service;
import com.kevin.springbootstudy.dao.UserMapper;
import com.kevin.springbootstudy.dao.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserMapper userDao;
@Transactional
public int insert(User user){
int i= userDao.insert(user);
if(i==1){
throw new RuntimeException("error");
}
return i;
}
}
3)再次测试
调用http://127.0.0.1:8081/addUser?id=4&name=kevin4后,返回异常,数据库没有增加相应的user记录,这就是我们想要的结果。
1)transaction.xml文件
2)引入文件@ImportResource(“classpath:transaction.xml”)
1)pom.xml引入aop
org.springframework.boot
spring-boot-starter-aop
2)增加一个事务管理的类
@Aspect
@Configuration
public class TransactionAdviceConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.***.service..*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute txRequired = new DefaultTransactionAttribute();
txRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txRequiredReadonly = new DefaultTransactionAttribute();
txRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txRequiredReadonly.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("get*", txRequiredReadonly);
source.addTransactionalMethod("query*", txRequiredReadonly);
source.addTransactionalMethod("find*", txRequiredReadonly);
source.addTransactionalMethod("*", txRequired);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
3)部分方法需要单独处理事务,也可以配合@Transactional一起使用
1)spring推荐在具体类上使用@Transactional,而不是在接口上声明
2)@Transactional声明在类上,则对所有的public方法有效
3)使用了@Transactional的方法,被同一个类里面的未使用@Transactional的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。
注:目录结构如下
参考
https://docs.spring.io/spring/docs/5.1.4.RELEASE/spring-framework-reference/data-access.html#transaction-declarative
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html
https://blog.csdn.net/nextyu/article/details/78669997