两个操作要么同时成功,要么同时失败;
事务的一致性;
以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作;
用来保证一致性,即service方法里的多个dao操作,要么同时成功,要么同时失败;
下面模拟用户转账,a用户转账给b用户200元;需要事务管理;
项目结构:
1.代码:
com.cy.entity.Account.java;
package com.cy.entity;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;/** * 账户实体 * @author CY * */@Entity@Table(name="t_account")public class Account { @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; } }
账户dao接口:com.cy.dao.AccountDao.java:
package com.cy.dao;import org.springframework.data.jpa.repository.JpaRepository;import com.cy.entity.Account;/** * 账户Dao接口 * JpaRepository第二个参数是主键类型 * @author CY * */public interface AccountDao extends JpaRepository {}
账户service接口:com.cy.service.AccountService.java:
package com.cy.service;/** * 账户Service接口 * @author CY * */public interface AccountService { /** * 从fromUser转账到toUser,account钱; * @param fromUser * @param toUser * @param account */ public void transferAccounts(int fromUser, int toUser, float account);}
账户接口实现类:com.cy.service.impl.AccountServiceImpl.java;
package com.cy.service.impl;import javax.annotation.Resource;import javax.transaction.Transactional;import org.springframework.stereotype.Service;import com.cy.dao.AccountDao;import com.cy.entity.Account;import com.cy.service.AccountService;/** * 账户service实现类 * @author CY * */@Service("accountService")public class AccountServiceImpl implements AccountService{ @Resource private AccountDao accountDao; /** * 从A用户转账到B用户account元; * 也就是两个操作: * A用户减去accout元,B用户加上account元 */ @Override @Transactional public void transferAccounts(int fromUser, int toUser, float account) { Account a = accountDao.getOne(fromUser); a.setBalance(a.getBalance() - account); accountDao.save(a); Account b = accountDao.getOne(toUser); b.setBalance(b.getBalance() + account); int i = 1/0; //这里制造个异常 accountDao.save(b); } }
com.cy.controller.AccountController.java来模拟用户转账:
这里返回json数据格式,成功ok,失败no
package com.cy.controller;import javax.annotation.Resource;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.cy.service.AccountService;/** * 账户Controller层 * @author CY * */@RestController@RequestMapping("/account")public class AccountController { @Resource private AccountService accountService; @RequestMapping("/transfer") public String transferAccount(){ try{ accountService.transferAccounts(1, 2, 200); return "ok"; }catch(Exception e){ return "no"; } }}
2.测试:
启动项目,查看新建的表t_account:
mysql> desc t_account;+-----------+-------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-----------+-------------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || balance | float | NO | | NULL | || user_name | varchar(50) | YES | | NULL | |+-----------+-------------+------+-----+---------+----------------+
弄点数据:
mysql> select * from t_account;+----+---------+-----------+| id | balance | user_name |+----+---------+-----------+| 1 | 700 | zhangsan || 2 | 300 | lisi |+----+---------+-----------+
浏览器http://localhost/account/transfer:
1)显示no,说明转账失败;
2)数据库数据,zhangsan仍然是700,lisi仍然是300,保证了数据一致性;
查看发出的sql:
Hibernate: select account0_.id as id1_0_0_, account0_.balance as balance2_0_0_, account0_.user_name as user_nam3_0_0_ from t_account account0_ where account0_.id=?Hibernate: select account0_.id as id1_0_0_, account0_.balance as balance2_0_0_, account0_.user_name as user_nam3_0_0_ from t_account account0_ where account0_.id=?
没有执行保存,全部弄完了才保存;
说明:
这里使用的是:import javax.transaction.Transactional;(这个是jpa规范)
使用import org.springframework.transaction.annotation.Transactional也行;(这个spring实现了jpa规范)