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

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

时间: 2024-10-08 10:53:35

SpringBoot之事务管理Transactional的相关文章

springboot mybatis 事务管理

本文主要讲述springboot提供的声明式的事务管理机制. 一.一些概念 声明式的事务管理是基于AOP的,在springboot中可以通过@Transactional注解的方式获得支持,这种方式的优点是: 1)非侵入式,业务逻辑不受事务管理代码的污染. 2)方法级别的事务回滚,合理划分方法的粒度可以做到符合各种业务场景的事务管理. 本文使用目前最常用的mybatis框架来配置springboot的事务管理机制.下面进入配置方法介绍. 二.springboot mybatis事务配置 1.看一下

springboot的事务管理

Spring Boot中的事务管理 原创 2016-05-27 翟永超 Spring Boot 被围观 29955 次 什么是事务? 我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合.由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操作数据的并不可靠,需要在这种情况下进行回退. 事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务

【Spring Boot学习之四】Spring Boot事务管理

环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 一.springboot整合事务事务分类:编程事务.声明事务(XML.注解),推荐使用注解方式,springboot默认集成事物,只主要在方法上加上@Transactional即可1.controller package com.wjy.controller; import org.springframework.beans.factory.annotation.Autowired; import org.spri

sping 对 hibernate进行事务管理--Annotation

1. UserServiceTest.java: package com.bjsxt.service; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bjsxt.model.User; //Dependency Inj

spring05-Spring事务管理

事务的第一个方面是传播行为(propagation behavior).当事务方法被另一个事务方法调用时,必须指定事务应该如何传播.例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行.Spring定义了七种传播行为: 传播行为 含义 PROPAGATION_REQUIRED 表示当前方法必须运行在事务中.如果当前事务存在,方法将会在该事务中运行.否则,会启动一个新的事务 PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,

@Transactional(事务讲解)和springboot 整合事务

概述 事务在编程中分为两种:声明式事务处理和编程式事务处理 编程式事务处理:编码方式实现事务管理,常与模版类TransactionTemplate(推荐使用) 在业务代码中实现事务. 可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现. 声明式事务处理: 声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transac

SSM框架中使用Spring的@Transactional注解进行事务管理

一 介绍 在企业级应用中,保护数据的完整性是非常重要的一件事.因此不管应用的性能是多么的高.界面是多么的好看,如果在转账的过程中出现了意外导致用户的账号金额发生错误,那么这样的应用程序也是不可接受的 数据库的事务管理可以有效地保护数据的完整性(PS:关于数据库的事务管理基础可以参考我以前写过的这篇文章:http://www.zifangsky.cn/385.html),但是原生态的事务操作需要写不少的代码,无疑是非常麻烦的.在使用了Spring框架的应用中,我们可以使用@Transactiona

spring,mybatis事务管理配置与@Transactional注解使用

spring,mybatis事务管理配置与@Transactional注解使用[转] 概述事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects) 支持声明式事务管理,特别是基

转 Spring @Transactional 声明式事务管理 getCurrentSession

Spring @Transactional声明式事务管理  getCurrentSession   在Spring @Transactional声明式事务管理的配置中,hibernate.current_session_context_class=thread- 这一句是不能加的-加了就会出错..那为什么不能加呢? 那是因为在Spring事务管理中,current Session是绑定到SpringSessionContext中的,而不是ThreadLocalSessionContext中的 先