Spring(3):声明式事务管理案例-转账(xml、注解)

1 编写转账案例,引出事务管理问题

需求:账号转账,Tom账号取出1000元,存放到Jack账号上

1.1 建表脚本(MySQL)

 CREATE TABLE t_account  (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) NOT NULL,money DOUBLE DEFAULT NULL,PRIMARY KEY (id)
)  

INSERT INTO `t_account` (`id`, `name`, `money`) VALUES ('1', 'tom', '1000');
INSERT INTO `t_account` (`id`, `name`, `money`) VALUES ('2', 'jack', '1100');
INSERT INTO `t_account` (`id`, `name`, `money`) VALUES ('3', 'rose', '2000');

1.2 新建工程

第一步:新建一个maven项目

第二步:引入依赖和applicationContext.xml配置文件和log4j.properties文件和db.properties文件:

pom.xml:

    <dependencies><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version></dependency><!-- spring核心包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.8.RELEASE</version></dependency><!-- spring集成测试 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.2.8.RELEASE</version></dependency><!-- spring事物管理 --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.2.8.RELEASE</version></dependency><!-- c3p0数据源 --><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency><!-- 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- 注解开发切面包 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.1</version></dependency></dependencies>

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>

log4j.properties:

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=info, stdout

db.properties:

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.222.156:3306/spring?characterEncoding=utf8&useSSL=false
jdbc.user=root
jdbc.password=123456

第三步:创建IAccountDao接口

创建AccounDaoImpl实现类,实现了IAccountDao接口

账户操作持久层

技术方案:jdbctempate

package com.example.demo.dao;public interface IAccountDao {// 转出public void out(String name, Double money);// 转入public void in(String name, Double money);
}

第四步:建立service层,创建IAccountService接口,编写转账的业务代码:

package com.example.demo.service;public interface IAccountService {//转账业务:public void transfer(String outName,String inName,Double money);
}

package com.example.demo.service.impl;import com.example.demo.dao.IAccountDao;
import com.example.demo.service.IAccountService;public class AccountServiceImpl implements IAccountService {// 注入daoprivate IAccountDao accountDao;public void setAccountDao(IAccountDao accountDao) {this.accountDao = accountDao;}// 转账业务public void transfer(String outName, String inName, Double money) {// 先转出accountDao.out(outName, money);// 再转入accountDao.in(inName, money);}
}

第五步: 将对象配置到spring工厂

applicationContext.xml文件添加配置

    <!-- 引入配置文件 --><context:property-placeholder location="classpath:db.properties" /><!-- 配置数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driverClass}" /><property name="jdbcUrl" value="${jdbc.url}" /><property name="user" value="${jdbc.user}" /><property name="password" value="${jdbc.password}" /></bean><!-- 管理dao和service --><bean id="accountDao" class="com.example.demo.dao.impl.AccountDaoImpl"><!-- 注入数据源 --><property name="dataSource" ref="dataSource" /></bean><bean id="accountService" class="com.example.demo.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property></bean>

第六步:使用SpringTest进行测试

package com.example.demo.service.impl;import com.example.demo.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;//集成spring测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AccountServiceImplTest {//注入测试对象@Autowiredprivate IAccountService accountService;@Testpublic void testTransfer() {accountService.transfer("tom", "jack", 1000d);}}

但是发现问题:

事务管理问题:在Service层没有事务的情况下,如果出现异常,则会转账不成功,数据异常。

在转账方法中添加如下异常:

运行前:

运行后:

事务未生效。

注意:如果不配置事务,那么每一个数据库的操作都是单独的一个事务。

2 XML配置方式添加事务管理(tx、aop元素)

【操作思路】:aop三步走

  1. 确定目标:需要对AccountService 的 transfer方法,配置切入点
  2. 需要Advice (环绕通知),方法前开启事务,方法后提交关闭事务
  3. 配置切面和切入点

配置Advice通知:

Spring为简化事务的配置,提供了**<tx:advice>**来配置事务管理,也可以理解为该标签是spring为你实现好了的事务的通知增强方案。

    <!-- 配置事物管理器 --><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 配置事物通知 --><!-- transaction-manager: 指定事物管理器的id,如果事物管理器的id为transactionManager的话 该属性可以省略(缺省值) --><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 配置事物管理细则(事物定义信息) --><tx:attributes><!-- 需要被增强(事物 管理)的方法 --><tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"read-only="false" timeout="-1" /></tx:attributes></tx:advice><!-- 配置切入点和切面 --><aop:config><aop:pointcut expression="bean(*Service)" id="mycut" /><aop:advisor advice-ref="txAdvice" pointcut-ref="mycut" /></aop:config>

使用AccountServiceImplTest.java测试:数据正常!

事物添加的前后对比

没有添加事务:

两个方法分属不同事务。

添加事务后:

分属同一事务

【注意】如果不配置,则走默认的事务(默认事务是每个数据库操作都是一个事务,相当于没事务),所以我们开发时需要配置事务。

3 注解配置方式添加事务管理 @Transactional

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/320800.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无监督学习-聚类算法(k-means)

无监督学习-聚类算法 1、聚类介绍 1.1、聚类作用 知识发现异常值检测特征提取 数据压缩的例子 1.2、有监督与无监督学习 有监督&#xff1a; 给定训练集X和标签Y选择模型 学习&#xff08;目标函数的最优化&#xff09;生成模型&#xff08;本质上是一组参数、方程&#x…

5G随身WiFi的口碑榜第一名到底怎么样?高性价比高口碑5G随身wifi推荐,5G随身WiFi哪个牌子最好用

对于格行5G随身WiFi一经发布就可以占据各大电商平台的口碑榜第一名和好评榜第一名&#xff0c;很多朋友表示不解这是怎么做到的&#xff1f;那么今天就由小编来详细介绍一下这款产品&#xff0c;为大家详细分析格行5G随身WiFi是怎么做到的。 品牌实力&#xff1a;格行作为深耕物…

快速跳闸中间继电器 RXMS1-RK216 066-AD 24V 柜内安装,板后接线带中座

系列型号 RXMS1 RK 216 437快速跳闸继电器&#xff1b;RXMS1 RK 216 237快速跳闸继电器&#xff1b; RXMS1 RK 216 449快速跳闸继电器&#xff1b;RXMS1 RK 216 249快速跳闸继电器&#xff1b; RXMS1 RK 216 450快速跳闸继电器&#xff1b;RXMS1 RK 216 250快速跳闸继电器&…

计划任务at crontab

一&#xff0c;一次性的计划任务 at &#xff08;一&#xff09;at相关命令 at 时间 ctrl d 提交 atq 查看计划任务 atrm 任务序号列 可以删除任务 &#xff08;二&#xff09;at 相关配置文件 …

nginx配置图片服务器

目录 一&#xff1a;访问流程 二&#xff1a;缓存服务器配置 三&#xff1a;上传图片直接上传到图片服务器 四&#xff1a;加快图片访问 一&#xff1a;访问流程 访问缓存服务器(上面安装nginx反向代理到图片服务器&#xff0c;对外提供服务)->图片服务器 二&#xff1…

详细解读QLC SSD无效编程问题-2

作者通过SimpleSSD仿真模型&#xff0c;采用SLCQLC混合模式来开展进一步的验证工作。评估过程中&#xff0c;当写入请求到达固态硬盘时&#xff0c;首先会被写入缓存&#xff08;DRAM&#xff09;&#xff0c;然后才被回写到NAND。文中引入了一个名叫做LRU(Least Recently Used…

JOSEF约瑟 定时限过流继电器 JSL-21/5 柜内安装,板前接线 实物图

系列型号&#xff1a; JSL-11定时限过流继电器&#xff1b;JSL-12定时限过流继电器; JSL-13定时限过流继电器&#xff1b;JSL-14定时限过流继电器&#xff1b; JSL-15定时限过流继电器&#xff1b;JSL-16定时限过流继电器; JSL-21定时限过流继电器&#xff1b;JSL-22定时限过流…

HTML如何设置多图片上传,并限制格式类型

在HTML如何设置多图片上传&#xff0c;并限制格式类型为jpg和png格式。 <input type"file" name"fileInput" id"fileInput"> 上面这行代码&#xff0c;只支持单个文件上传&#xff0c;且不支持文件类型过滤&#xff0c;在实际开发过程中&…

C++|【25】构造函数和【26】析构函数

为什么需要构造函数 创造一个实体类&#xff0c;而未将其内部变量提前赋予新值&#xff0c;并强行进行调用&#xff0c;将会随机分配上一个新的值。 而使用构造函数可以确保&#xff0c;可以使得变量有一个稳定的初始值。 Init函数需要人为去调用&#xff0c;而采用构造函数&am…

新手必看!STM32通用定时器-输入捕获!

一、用途与工作原理 用途&#xff1a;用于测量信号的参数&#xff0c;比如周期和频率。   工作原理&#xff1a;在输入捕获模式下&#xff0c;当捕获单元捕捉到外部信号的有效边沿(上升沿/下降 沿/双边沿)时&#xff0c;将计数器的当前值锁存到捕获/比较寄存器TIMx_CCR&#…

014、枚举与模式匹配

枚举类型&#xff0c;通常也被简称为枚举&#xff0c;它允许我们列举所有可能的值来定义一个类型。在本篇文章中&#xff0c;我们首先会定义并使用一个枚举&#xff0c;以向你展示枚举是如何连同数据来一起编码信息的。 接着&#xff0c;我们会讨论一个特别有用的枚举&#xff…

一文详解云渲染是什么?选择云渲染农场优势是什么?

渲染行业的中最热门的话题除了真实的场景效果&#xff0c;还有渲染参数与渲染速度的讨论&#xff0c;本地电脑硬件高渲染速度自然比较快&#xff0c;但是个人的成本也通常会让大家无法承受&#xff0c;且本地电脑在遇到动画渲染时&#xff0c;往往是更不上速度的&#xff0c;这…