以前學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即可。