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 }
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 }
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 }
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 }
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 }
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
我们执行启动类
浏览器输入: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 }
这时候 扣钱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 }
我们恢复下数据700 300
然后再重启启动类,
浏览器输入:http://localhost/account/transfer
运行NO
但是数据库数据没变化 说明启动作用了。
OK,保证事务一致性,方法上加Transactional即可。