两个操作要么同时成功,要么同时失败;
事务的一致性;
以前学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<T, ID>第二个参数是主键类型 * @author CY * */ public interface AccountDao extends JpaRepository<Account, Integer>{ }
账户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规范)