• SpringBoot之事务管理Transactional


    以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作;

    用来保证一致性,即service方法里的多个dao操作,要么同时成功,要么同时失败;

    springboot下的话 一个@Transactional即可搞定;

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

    设计如下:

    Account类

     1 package com.hik.entity;
     2 
     3 import javax.persistence.Column;
     4 import javax.persistence.Entity;
     5 import javax.persistence.GeneratedValue;
     6 import javax.persistence.Id;
     7 import javax.persistence.Table;
     8 
     9 /**
    10  * 账户实体
    11  * @author jed
    12  *
    13  */
    14 @Entity
    15 @Table(name="t_account")
    16 public class Account {
    17 
    18     @Id
    19     @GeneratedValue
    20     private Integer id;
    21     
    22     @Column(length=50)
    23     private String userName;
    24     
    25     private float balance;
    26 
    27     public Integer getId() {
    28         return id;
    29     }
    30 
    31     public void setId(Integer id) {
    32         this.id = id;
    33     }
    34 
    35     public String getUserName() {
    36         return userName;
    37     }
    38 
    39     public void setUserName(String userName) {
    40         this.userName = userName;
    41     }
    42 
    43     public float getBalance() {
    44         return balance;
    45     }
    46 
    47     public void setBalance(float balance) {
    48         this.balance = balance;
    49     }
    50     
    51     
    52 }
    View Code

    id 编号 userName用户名 balance余额

    运行启动类,数据库里我们加两个数据

    新建AccountDao接口

     1 package com.hik.dao;
     2 
     3 import org.springframework.data.jpa.repository.JpaRepository;
     4 
     5 import com.hik.entity.Account;
     6 
     7 /**
     8  *  账户Dao接口
     9  * @author jed
    10  *
    11  */
    12 public interface AccountDao extends JpaRepository<Account, Integer>{
    13     
    14 }
    View Code

    AccountService接口

     1 package com.hik.service;
     2 
     3 /**
     4  * 帐号Service接口
     5  * @author jed
     6  *
     7  */
     8 public interface AccountService {
     9 
    10     public void transferAccounts(int fromUser,int toUser,float account);
    11 }
    View Code

    AccountServiceImpl接口实现类

     1 package com.hik.service.impl;
     2 
     3 import javax.annotation.Resource;
     4 
     5 import org.springframework.stereotype.Service;
     6 
     7 import com.hik.dao.AccountDao;
     8 import com.hik.entity.Account;
     9 import com.hik.service.AccountService;
    10 
    11 /**
    12  * 帐号Service实现类
    13  * @author jed
    14  *
    15  */
    16 @Service("accountService")
    17 public class AccountServiceImpl implements AccountService{
    18 
    19     @Resource
    20     private AccountDao accountDao;
    21     
    22     @Override
    23     public void transferAccounts(int fromUser, int toUser, float account) {
    24         Account fromUserAccount = accountDao.getOne(fromUser);
    25         fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
    26         accountDao.save(fromUserAccount); // fromUser扣钱
    27         
    28         Account toUserAccount = accountDao.getOne(toUser);
    29         toUserAccount.setBalance(toUserAccount.getBalance()+account);
    30         accountDao.save(toUserAccount);// toUser加钱
    31     }
    32 
    33 }
    View Code

    AccountController类

     1 package com.hik.Controller;
     2 
     3 import javax.annotation.Resource;
     4 
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.RestController;
     7 
     8 import com.hik.service.AccountService;
     9 
    10 /**
    11  * 账户Controoler类
    12  * @author jed
    13  *
    14  */
    15 @RestController
    16 @RequestMapping("/account")
    17 public class AccountController {
    18     
    19     @Resource
    20     private AccountService accountService;
    21 
    22     @RequestMapping("/transfer")
    23     public String transferAccounts() {
    24         try {
    25             accountService.transferAccounts(1, 2, 200);
    26             return "ok";
    27         }catch(Exception e) {
    28             return "no";
    29         }
    30     }
    31 }
    View Code

    application.yml

     1 server: 
     2     port: 80
     3     context-path: /
     4 
     5 spring: 
     6     datasource: 
     7       driver-class-name: com.mysql.jdbc.Driver
     8       url: jdbc:mysql://localhost:3306/db_bank
     9       username: root
    10       password: passwd
    11     jpa: 
    12       hibernate:
    13         ddl-auto: update
    14       show-sql: true
    View Code

    我们执行启动类

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

    运行OK

    查看数据库表

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

    现在我们把service层方法改下 

     1 package com.hik.service.impl;
     2 
     3 import javax.annotation.Resource;
     4 
     5 import org.springframework.stereotype.Service;
     6 
     7 import com.hik.dao.AccountDao;
     8 import com.hik.entity.Account;
     9 import com.hik.service.AccountService;
    10 
    11 /**
    12  * 帐号Service实现类
    13  * @author jed
    14  *
    15  */
    16 @Service("accountService")
    17 public class AccountServiceImpl implements AccountService{
    18 
    19     @Resource
    20     private AccountDao accountDao;
    21     
    22     @Override
    23     public void transferAccounts(int fromUser, int toUser, float account) {
    24         Account fromUserAccount = accountDao.getOne(fromUser);
    25         fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
    26         accountDao.save(fromUserAccount); // fromUser扣钱
    27         
    28         Account toUserAccount = accountDao.getOne(toUser);
    29         toUserAccount.setBalance(toUserAccount.getBalance()+account);
    30         int zero =1/0;
    31         accountDao.save(toUserAccount);// toUser加钱
    32     }
    33 
    34 }
    View Code

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

    我们重启启动类

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

    运行NO

    查看数据库

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

    这时候 我们需要用上事务

    在service方法上加上@Transactional即可

     1 package com.hik.service.impl;
     2 
     3 import javax.annotation.Resource;
     4 import javax.transaction.Transactional;
     5 
     6 import org.springframework.stereotype.Service;
     7 
     8 import com.hik.dao.AccountDao;
     9 import com.hik.entity.Account;
    10 import com.hik.service.AccountService;
    11 
    12 /**
    13  * 帐号Service实现类
    14  * @author jed
    15  *
    16  */
    17 @Service("accountService")
    18 public class AccountServiceImpl implements AccountService{
    19 
    20     @Resource
    21     private AccountDao accountDao;
    22     
    23     @Transactional
    24     public void transferAccounts(int fromUser, int toUser, float account) {
    25         Account fromUserAccount = accountDao.getOne(fromUser);
    26         fromUserAccount.setBalance(fromUserAccount.getBalance()-account);
    27         accountDao.save(fromUserAccount); // fromUser扣钱
    28         
    29         Account toUserAccount = accountDao.getOne(toUser);
    30         toUserAccount.setBalance(toUserAccount.getBalance()+account);
    31         int zero =1/0;
    32         accountDao.save(toUserAccount);// toUser加钱
    33     }
    34 
    35 }
    View Code

    我们恢复下数据700  300

    然后再重启启动类,

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

    运行NO

     

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

     

     OK,保证事务一致性,方法上加Transactional即可。

  • 相关阅读:
    vue中的组件传值
    Object中defineProperty数据描述
    promiseall的使用场景
    babel安装及使用
    checkbox属性checked="checked"已有,但却不显示打勾的解决办法
    【转载】表单验证<AngularJs>
    CSS3 :nth-child()伪类选择器
    【转载】浏览器加载和渲染html的顺序
    css制作的61种图像
    网站链接样式设置
  • 原文地址:https://www.cnblogs.com/jedjia/p/transactional.html
Copyright © 2020-2023  润新知