Springboot集成Mybatis之事务

项目中的读写、修改、删除数据的操作如果发生异常,常常会导致已写入、修改、删除的数据无法回退到最开始的情况。这种情况下,我们就要依赖Spring的事务机制来实现回退操作。
下面在ibatis项目的项目上简单讲一下如何使用事务:
1、新建Account类

import java.io.Serializable;

@Data
@ToString
public class Account implements Serializable {
    private Integer id;//编号
    private String username;//用户名
    private float balance;//余额
}

2、新建AccountMapper接口

import com.batis.model.Account;
import org.springframework.stereotype.Repository;

@Repository
public interface AccountMapper {
    Account findOne(Integer id);
    void update(Account account);
}

3、在resources目录下的mapping目录新建AccountMapping.xml,实现AccountMapper接口中的sql

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.batis.mapper.AccountMapper">
    <!-- 开启二级缓存 -->
    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"></cache>
    <resultMap id="BaseResultMap" type="com.batis.model.Account">
        <result column="id" jdbcType="INTEGER" property="id" />
        <result column="username" jdbcType="VARCHAR" property="username" />
        <result column="balance" jdbcType="FLOAT" property="balance" />
    </resultMap>

    <sql id="baseSql">
        select id, username, balance from t_account
    </sql>

    <select id="findOne" resultMap="BaseResultMap" parameterType="java.lang.Integer">
        <include refid="baseSql"/> where id = #{id}
    </select>

    <update id="update" parameterType="com.batis.model.Account">
        UPDATE t_account SET username = #{username}, balance = #{balance}
        WHERE id = #{id}
    </update>
</mapper>

4、新建AccountService接口类和AccountServiceImpl实现类
AccountService接口类:

public interface AccountService {
    /**
     * 转账
     * @param fromAccountId
     * @param toAccountId
     * @param money
     */
    public void transferAccounts(int fromAccountId, int toAccountId, float money);
}

AccountServiceImpl实现类:

import com.batis.mapper.AccountMapper;
import com.batis.model.Account;
import com.batis.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountMapper accountMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void transferAccounts(int fromAccountId, int toAccountId, float money) {
        Account fromAccount = accountMapper.findOne(fromAccountId);
        fromAccount.setBalance(fromAccount.getBalance() - money);
        accountMapper.update(fromAccount);

        int a = 2 / 0;//报错处
        Account toAccount = accountMapper.findOne(toAccountId);
        toAccount.setBalance(toAccount.getBalance() + money);
        accountMapper.update(toAccount);
    }
}

@Transactional注解的属性:
value:可选的限定描述符,指定使用的事务管理器
propagation:可选的事务传播行为设置
isolation:可选的事务隔离级别设置
timeout:事务超时时间设置,默认值为-1表示永不超时
readOnly:读写或只读事务,默认读写,设置为true表示只读,false表示可读写,默认为false
rollbackFor:导致事务回滚的异常类数组
rollbackForClassName:导致事务回滚的异常类名字数组
noRollbackFor:不会导致事务回滚的异常类数组
noRollbackForClassName:不会导致事务回滚的异常类名字数组
5、新建AccountController控制器类

import com.batis.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/account")
public class AccountController {
    @Autowired
    private AccountService accountService;

    @RequestMapping(value = "/transfer", method = RequestMethod.GET)
    public String transferAccounts() {
        try {
            //1号zhangsan 给2号lisi 转账200元
            accountService.transferAccounts(1, 2, 200);
            return "ok";
        } catch (Exception e) {
            return "no";
        }
    }
}

6、在mysql的test库新建t_account表,并插入2条数据

CREATE TABLE `t_account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL COMMENT '用户名',
  `balance` float(10,2) DEFAULT NULL COMMENT '余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `test`.`t_account`(`id`, `username`, `balance`) VALUES (1, 'zhangsan', 1000.00);
INSERT INTO `test`.`t_account`(`id`, `username`, `balance`) VALUES (2, 'lisi', 1000.00);

7、启动ibatis项目进行测试,在浏览器地址栏输入http://localhost:8080/account/transfer
1)先注释掉AccountServiceImpl实现类中的@Transactional,然后可以看到数据库zhangsan转出了200,但是lisi并没有增加金额,说明报错后数据没有回滚
在这里插入图片描述
2)去掉AccountServiceImpl实现类中注解@Transactional的注释,恢复张三的余额为1000,重新在浏览器输入http://localhost:8080/account/transfer进行测试,重新查看数据库中的结果
在这里插入图片描述
可以看到,结果张三和李四的金额都是1000,说明在执行转账的过程中,发生异常的情况下数据回滚了
至此Springboot集成Mybatis事务的讲解已经完成,测试也符合预期!
有可以改进的地方希望诸位同学不要吝惜笔墨,加以指正,万分感谢!

参考链接:
https://www.cnblogs.com/zuoxh/p/9724193.html
https://www.cnblogs.com/wxc-xiaohuang/p/9471971.html
https://blog.csdn.net/qq_38366063/article/details/92425018

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值