MyBatis-Plus操作基本就给大家介绍几个就行,大概用法都差不多,一个跑通了,其他的也就都一样,但是在完成业务功能的时候,多去思考如何更好的把IService中的方法混合使用,除了CRUDB(增查改删批)之外,还有一个重要的课题就是事务,面试的时候事务经常会被问到,多准备准备八股文,这一节用两种方式去使用事务。
第一种最简单,通过注解的方式直接去给一个method添加事务。这里面试经常遇到一个八股文考题:@Transactional为什么有时候会失效?答案大致是:1、非public的方法,这是受Springboot切面导致的,@Transactional是通过AOP实现的,AOP只有public才生效,想想也对,非public的外部又调不到就没有AOP。2、try-catch影响了事务,因为事务本身就是通过Exception感知到的,代码里加了try-catch很可能就破坏了它的感知能力。3、如果@Transactional方法里数据库操作正好在当前类的另外一个方法里,也不生效,因为调用当前类的方法是直接用了this,绕过了AOP。(感觉这个解释真八股啊。。。。)4、@Transactional可以设置时间长短,时间太短就不停地回滚,也算一种无效。
第二种其实是Springboot的事务实现方式——编程式事务,这种方式好处是更精细,比如有多个sql操作在一个方法体里的时候,可以只给其中一部分添加事务,而第一种注解的方式就是整个方法体全部加上事务了。
添加一个事务的Configuration,为了提供后续能通过@AutoWired获取DataSourceTransactionManager这个对象,把DataSourceTransactionManager注入到IOC里,启动的时候自动实例化,用起来更优雅:
package com.mj.mybatisplus.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.sql.DataSource;
@EnableAutoConfiguration
@EnableTransactionManagement
public class TransactionConfig {
@Bean(name = "dataSourceTransactionManager")
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
修改IUserService,添加两个方法:
package com.mj.mybatisplus.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mj.mybatisplus.po.User;
public interface IUserService extends IService<User> {
//注解使用事务
boolean updateWithTransaction(String id);
//编程方式使用事务
boolean updateWithTransactionManager(String id);
}
修改UserServiceImpl,实现这两个方法,测试的时候在这两个方法里故意加一下异常就行:
package com.mj.mybatisplus.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mj.mybatisplus.mapper.UserMapper;
import com.mj.mybatisplus.po.User;
import com.mj.mybatisplus.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private PlatformTransactionManager transactionManager;
@Override
@Transactional
//@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略
public boolean updateWithTransaction(String id) {
//如果抛出异常,事务将回滚
User user = getById(id);
user.setUsername("guangyu");
return updateById(user);
}
@Override
//编程式事务管理
public boolean updateWithTransactionManager(String id) {
// 创建事务定义
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 设置事务的隔离级别
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 设置事务的传播行为
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 获取事务对象
TransactionStatus status = transactionManager.getTransaction(definition);
try {
// 更新用户信息
User user = getById(id);
user.setUsername("caocao");
updateById(user);
// 提交事务
transactionManager.commit(status);
return true;
} catch (Exception e) {
// 发生异常,回滚事务
transactionManager.rollback(status);
throw e;
}
}
}
修改UserController,添加两个测试接口即可:
@PostMapping("/updateWithTransaction/{id}")
@Parameter(name = "id", description = "用户id", in = ParameterIn.PATH)
@Operation(summary = "事务更新用户", description = "事务更新用户")
public ResponseEntity<Boolean> updateWithTransaction(@PathVariable("id") String id) {
return ResponseEntity.ok(userService.updateWithTransaction(id));
}
@PostMapping("/updateWithTransactionManager/{id}")
@Parameter(name = "id", description = "用户id", in = ParameterIn.PATH)
@Operation(summary = "编程式事务更新用户", description = "编程式事务更新用户")
public ResponseEntity<Boolean> updateWithTransactionManager(@PathVariable("id") String id) {
return ResponseEntity.ok(userService.updateWithTransactionManager(id));
}