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即可。

原文地址:https://www.cnblogs.com/jedjia/p/transactional.html