SpringBoot+MyBatis-Plus使用教程(五)

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));
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值