spring有声明式事务和编程式事务,本篇看一下springboot下的@Transactional

1. 前言

springboot下的@Transactional

2.编码
我们这里搞一个实例,转账实例,A用户转账给B用户xx元

Account类

package com.jd.entity;

​

import javax.persistence.*;

@Entity

@Table(name="t_account")

public class Account {

    /**

     * id 编号

     */

    @Id

    @GeneratedValue

    private Integer id;

​

    /**

     * 用户名

     */

    @Column(length=50)

    private String userName;

​

    /**

     * 余额

     */

    private float balance;

​

    public Integer getId() {

        return id;

    }

​

    public void setId(Integer id) {

        this.id = id;

    }

​

    public String getUserName() {

        return userName;

    }

​

    public void setUserName(String userName) {

        this.userName = userName;

    }

​

    public float getBalance() {

        return balance;

    }

​

    public void setBalance(float balance) {

        this.balance = balance;

    }

}

1.启动启动类,会自动创建表t_account,我们插入两条数据(这里我练习还是使用之前 db_book 库,可以自己切换其他库)

insert into t_account values(1,700,'zhangsan');
insert into t_account values(2,300,'lisi');

代码请建立对应的包,可以参考我建立的包

2.新建AccountDao接口

package com.jd.dao;
​
import com.jd.entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
​
/**
 * Created by ${HeJD} on 2018/6/27.
 */
public interface AccountDao extends JpaRepository<Account, Integer> {
}


3.AccountService接口

 

package com.jd.service;
​
/**
 * Created by ${HeJD} on 2018/6/27.
 */
public interface AccountService {
    /**
     * 转账
     * @param fromUserId
     * @param toUserId
     * @param account
     */
    public void transferAccounts(int fromUserId,int toUserId,float account);
}


4.AccountServiceImpl接口实现类

 

package com.jd.service.serviceImp;
​
import com.jd.dao.AccountDao;
import com.jd.entity.Account;
import org.springframework.stereotype.Service;
import com.jd.service.AccountService;
import javax.annotation.Resource;
​
/**
 * Created by ${HeJD} on 2018/6/27.
 */
@Service("accountService")
public class AccountServiceImpl implements AccountService {
​
    @Resource
    private AccountDao accountDao;
​
    public void transferAccounts(int fromUserId,int toUserId,float account){
​
        Account fromUserAccount=accountDao.getOne(fromUserId);
        fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
        accountDao.save(fromUserAccount); // fromUser扣钱
​
        Account toUserAccount=accountDao.getOne(toUserId);
        toUserAccount.setBalance(toUserAccount.getBalance()+account);
        //假设转账的时候假如出现异常,业务类或业务方法中没有使用@Transactional控制事务,则会出现钱转出了,收钱人没有收到的情况
       // int zero = 1/0;  这里我们先把这个异常注释掉,稍后我们再打开
        accountDao.save(toUserAccount); // toUser加钱
    }
}


5.AccountController类

package com.jd.controller;
​
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jd.service.AccountService;
​
import javax.annotation.Resource;
​
/**
 * Created by ${HeJD} on 2018/6/27.
 */
​
@RestController
@RequestMapping("/account")
public class AccountController {
​
    @Resource
    private AccountService accountService;
​
    @RequestMapping("/transfer")
    public String transferAccounts(){
        try{
            //1号zhsnasan  给2号lisi 转账200元
            accountService.transferAccounts(1, 2, 200);
            return "ok";
        }catch(Exception e){
            return "no";
        }
    }
}

6.我们执行启动类

浏览器输入:http://localhost:8080/account/transfer

 

运行OK,没有事务控制的时候,没有异常的时候,转出的前与入账的钱是一致的,没有出现丢失的情况。

OK 我们先把数据恢复到700 300

现在我们把service层方法改下,抛出一个异常

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.transaction.Transactional;
​
@Service("accountService")
public class AccountServiceImpl implements AccountService {
​
    @Resource
    private AccountDao accountDao;
​
    /**
     * 转账
     *
     * @param fromUserId
     * @param toUserId
     * @param account
     */
    @Override
​
    public void transferAccounts(int fromUserId, int toUserId, float account) {
        Account fromUserAccount=accountDao.getOne(fromUserId);
        fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
        accountDao.save(fromUserAccount); // fromUser扣钱
​
        Account toUserAccount=accountDao.getOne(toUserId);
        toUserAccount.setBalance(toUserAccount.getBalance()+account);
​
        //假设转账的时候假如出现异常,业务类或业务方法中没有使用@Transactional控制事务,则会出现钱转出了,收钱人没有收到的情况
        int zero = 1/0;   //打开这个异常
        accountDao.save(toUserAccount); // toUser加钱
    }
}

这时候 扣钱dao能执行成功 加钱操作执行不了了 因为前面会报错。

我们重启启动类

浏览器输入:http://localhost:8080/account/transfer

 

运行NO

这时候 钱扣了 但是 没加钱 导致了数据不一致性!!!!

3.事务的使用
这时候 我们需要用上事务

在service类或方法上加上@Transactional即可,无需xml文件的配置,这也是springboot的优点

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

 

package com.jd.service.serviceImp;
​
import com.jd.dao.AccountDao;
import com.jd.entity.Account;
import org.springframework.stereotype.Service;
import com.jd.service.AccountService;
import org.springframework.transaction.annotation.Transactional;
​
import javax.annotation.Resource;
​
/**
 * Created by ${HeJD} on 2018/6/27.
 */
//添加事务注解,异常的时候能保证事务的一致性
​
@Service("accountService")
public class AccountServiceImpl implements AccountService {
​
    @Resource
    private AccountDao accountDao;
​
   @Transactional   
    public void transferAccounts(int fromUserId,int toUserId,float account){
​
        Account fromUserAccount=accountDao.getOne(fromUserId);
        fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
        accountDao.save(fromUserAccount); // fromUser扣钱
​
        Account toUserAccount=accountDao.getOne(toUserId);
        toUserAccount.setBalance(toUserAccount.getBalance()+account);
        //假设转账的时候假如出现异常,业务类或业务方法中没有使用@Transactional控制事务,则会出现钱转出了,收钱人没有收到的情况
        int zero = 1/0;  //这个异常照样是打开
        accountDao.save(toUserAccount); // toUser加钱
    }
}



我们恢复下数据700  300

然后再重启启动类,

浏览器输入:http://localhost:8080/account/transfer

运行NO

但是数据库数据没变化 说明启动作用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值