Spring事务(2):声明式事务管理案例-转账(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

步骤:

  1. 在需要管理事务的方法或者类上面 添加@Transactional 注解
  2. 配置注解驱动事务管理(事务管理注解生效的作用)(需要配置对特定持久层框架使用的事务管理器)

创建项目spring_transaction_anntx:

替换applicationContext.xml中的<bean> 配置为注解

改造dao:

package com.example.demo.dao.impl;import com.example.demo.dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;import javax.sql.DataSource;@Repository("accountDao")
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {//将数据源注入给父类,父类中需要通过数据源创建jdbctemplate@Autowiredpublic void setSuperDataSource(DataSource dataSource){super.setDataSource(dataSource);}public void out(String name, Double money) {String sql = "update t_account set money = money-? where name = ?";super.getJdbcTemplate().update(sql, money, name);}public void in(String name, Double money) {String sql = "update t_account set money = money+? where name = ?";super.getJdbcTemplate().update(sql, money, name);}
}

改造service:

package com.example.demo.service.impl;import com.example.demo.dao.IAccountDao;
import com.example.demo.service.IAccountService;
import org.springframework.stereotype.Service;@Service("accountService")
public class AccountServiceImpl implements IAccountService {// 注入dao@Autowiredprivate 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);}
}

在applicationContext.xml中配置注解扫描:

    <!-- 开启注解扫描 --><context:component-scan base-package="com.example.demo" />

测试方法是否能正常运行

以上步骤全部没问题后,开始配置注解方式的事物管理

第一步:配置 事物管理器:

在applicationContext.xml中,根据选用的持久层框架配置事物管理器:

    <!-- 配置事物管理器 --><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean>

第二步: 在需要管理事物的方法上添加@Transactional注解,表示对该方法进行事物管理

第三步:在applicationContext.xml中开启事物注解驱动,让@Transactional注解生效

<?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"><!-- 引入配置文件 --><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><!-- 开启注解扫描 --><context:component-scan base-package="com.example.demo" /><!-- 配置事物管理器 --><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!--配置事务注解驱动--><tx:annotation-driven transaction-manager="transactionManager" /></beans>

第四步:测试事物是否正常

提示:

如果 @Transactional 标注在 Class 上面, 那么将会对这个 Class 里面所有的 public 方法都包装事务方法。等同于该类的每个公有方法都放上了@Transactional。

如果某方法需要单独的事务定义,则需要在方法上加@Transactional来覆盖类上的标注声明。记住:方法级别的事务覆盖类级别的事务(就近原则)

package com.example.demo.service.impl;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.example.demo.dao.IAccountDao;
import com.example.demo.service.IAccountService;@Service("accountService")
@Transactional
// 放置在类上表示对该类中所有的方法都进行事物管理
public class AccountServiceImpl implements IAccountService {// 注入dao@Autowiredprivate IAccountDao accountDao;// 转账业务@Transactionalpublic void transfer(String outName, String inName, Double money) {// 先转出accountDao.out(outName, money);// 发生异常int i = 1 / 0;// 再转入accountDao.in(inName, money);}@Transactional(readOnly = true)// 当方法上的事物定义信息和类上的冲突时,就近原则使用方法上的配置public Double queryMoney(String name) {// TODO Auto-generated method stubreturn null;}}

4 小结-xml和注解的选择

XML配置方式和注解配置方式进行事务管理 哪种用的多?

XML方式,集中式维护,统一放置到applicationContext.xml文件中,缺点在于配置文件中的内容太多。

使用@Transactional注解进行事务管理,配置太分散,使用XML进行事务管理,属性集中配置,便于管理和维护

注意:以后的service的方法名字的命名,必须是上面规则,否则,不能被spring事务管理。!!!!

即以save开头的方法,update开头的方法,delete开头的方法,表示增删改的操作,故事务为可写

以find开头的方法,表示查询,故事务为只读

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

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

相关文章

Qt QLabel标签控件

文章目录 1 属性和方法1.1 文本1.2 对齐方式1.3 换行1.4 图像 2. 实例2.1 布局2.2 为标签添加背景色2.3 为标签添加图片2.4 代码实现 QLabeI是Qt中的标签类&#xff0c;通常用于显示提示性的文本&#xff0c;也可以显示图像 1 属性和方法 QLabel有很多属性&#xff0c;完整的可…

学习笔记 | Activiti7

什么是工作流&#xff1f; 业务流程。 举个例子: 假设有一个在线博客平台&#xff0c;我们要让一篇新的文章从作者的头脑里发表出来。整个过程可以分为以下几个步骤&#xff1a; 创建文章草稿 &#xff1a;作者登录博客平台&#xff0c;点击“写新文章”的按钮&#xff0c…

实习学习总结(2023-12-14---2024-1-08)

CS汉化 首先下载CSagent&#xff0c;百度网盘中有 按照如下放置目录 使用出现中文乱码 插件使用乱码主要跟cs客户端加载没有指定UTF-8编码有关 指定编码的字符&#xff1a;-Dfile.encodingUTF-8 上面的字段添加到启动脚本里面即可&#xff0c;如&#xff1a; java -Dfile.e…

与AI合作 -- 写一个modern c++单例工厂

目录 前言 提问 bard给出的答案 AI答案的问题 要求bard改进 人类智能 AI VS 人类 前言 通过本文读者可以学到modern C单例模式工厂模式的混合体&#xff0c;同时也能看到&#xff1a;如今AI发展到了怎样的智能程度&#xff1f;怎样让AI帮助我们快速完成实现头脑中的想法&…

进阶分布式链路追踪

另外我的新书RocketMQ消息中间件实战派上下册&#xff0c;在京东已经上架啦&#xff0c;目前都是5折&#xff0c;非常的实惠。 https://item.jd.com/14337086.html​编辑https://item.jd.com/14337086.html “RocketMQ消息中间件实战派上下册”是我既“Spring Cloud Alibaba微…

读元宇宙改变一切笔记03_元素(下)

1. 元素2&#xff1a;3D&#xff0c;互联网的下一个伟大迈进 1.1. 3D的必要性不仅仅是因为它预示着新事物的出现 1.1.1. 为了使人类文化和劳动实现从物理世界向数字世界的过渡&#xff0c;必须借助3D环境 1.2. 用户通过几乎源源不断的高分辨…

JVM工作原理与实战(十):类加载器-Java类加载器

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、介绍 二、扩展类加载器 三、通过扩展类加载器去加载用户jar包 1.放入/jre/lib/ext下进行扩展 2.使用参数进行扩展 四、应用程序类加载器 总结 前言 ​JVM作为Java程序的运行…

Python——运算符

num 1 num 1 print("num1:", num) num - 1 print("num-1:", num) num * 4 print("num*4:", num) num / 4 print("num/4:", num) num 3 num % 2 print("num%2:", num) num ** 2 print("num**2:", num) 运行结果…

【Linux Shell】10. 函数

文章目录 【 1. 函数的定义 】【 2. 函数参数 】 【 1. 函数的定义 】 所有函数在使用前必须定义 。这意味着必须将函数放在脚本开始部分&#xff0c;直至shell解释器首次发现它时&#xff0c;才可以使用。 调用函数仅使用其函数名即可 。 函数返回值在调用该函数后通过 $? 来…

我的阿里云服务器被攻击了

服务器被DDoS攻击最恶心&#xff0c;尤其是阿里云的服务器受攻击最频繁&#xff0c;因为黑客都知道阿里云服务器防御低&#xff0c;一但被攻击就会进入黑洞清洗&#xff0c;轻的IP停止半小时&#xff0c;重的停两个至24小时&#xff0c;给网站带来很严重的损失。而处理 ddos 攻…

华为ipv4+ipv6双栈加isis多拓扑配置案例

实现效果&#xff1a;sw1中的ipv4和ipv6地址能ping通sw2中的ipv4和ipv6地址 R2-R4为存IPV4连接&#xff0c;其它为ipv6和ipv4双连接 sw1 ipv6 interface Vlanif1 ipv6 enable ip address 10.0.11.1 255.255.255.0 ipv6 address 2001:DB8:11::1/64 interface MEth0/0/1 inter…

Java课程设计团队博客 —— 基于网页的时间管理系统

博客目录 1.项目简介2.项目采用的技术3.功能需求分析4.项目亮点5.主要功能截图6.Git地址7.总结 Java团队博客分工 姓名职务负责模块个人博客孙岚组长 资源文件路径和tomcat服务器的相关配置。 前端的页面设计与逻辑实现的代码编写。 Servlet前后端数据交互的编写。 用户登录和…

java Servlet体育馆运营管理系统myeclipse开发mysql数据库网页mvc模式java编程计算机网页设计

一、源码特点 JSP 体育馆运营管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统采用serlvetdaobean&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。 java Servlet体育馆运营管理系…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第六天-Linux信号(物联技术666)

更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机…

910b上跑Chatglm3-6b进行流式输出【pytorch框架】

文章目录 准备阶段避坑阶段添加代码结果展示 准备阶段 配套软件包Ascend-cann-toolkit和Ascend-cann-nnae适配昇腾的Pytorch适配昇腾的Torchvision Adapter下载ChatGLM3代码下载chatglm3-6b模型&#xff0c;或在modelscope里下载 避坑阶段 每个人的服务器都不一样&#xff0…

vue3 封装一个Tooltip 文字提示组件

效果图 默认展示icon图标&#xff0c;悬浮展示文字 如果slot有内容则展示对应内容 实现 用的是El-Tooltip组件 Element - The worlds most popular Vue UI framework 组件代码 <script setup lang"ts"> import { Icon } from /components/Icon import { ElTo…

超维空间M1无人机使用说明书——21、基于opencv的人脸识别

引言&#xff1a;M1型号无人机不仅提供了yolo进行物体识别&#xff0c;也增加了基于opencv的人脸识别功能包&#xff0c;仅需要启动摄像头和识别节点即可 链接: 源码链接 一、一键启动摄像头和人脸识别节点 roslaunch robot_bringup bringup_face_detect.launch无报错&#…

Django配置日志系统的最佳实践

概要 日志是跟踪应用行为、监控错误、性能分析和安全审计的重要工具。在Django框架中&#xff0c;合理配置日志系统可以帮助开发者有效管理项目运行过程中的关键信息。本文将详细介绍Django日志系统的最佳实践。 日志系统概述 Django使用Python的 logging 模块来实现日志系统…

掌握Lazada API接口:开启电商开发新篇章,引领业务增长潮流

一、概述 Lazada API接口是Lazada平台提供的软件开发工具包&#xff0c;它允许第三方开发者通过编程方式访问Lazada平台上的商品、订单、用户等数据&#xff0c;并执行相关操作。通过使用Lazada API接口&#xff0c;开发者可以快速构建与Lazada平台集成的应用程序&#xff0c;…

WPF 基础入门(资源字典)

资源字典 每个Resources属性存储着一个资源字典集合。如果希望在多个项目之间共享资源的话&#xff0c;就可以创建一个资源字典。资源字段是一个简单的XAML文档&#xff0c;该文档就是用于存储资源的&#xff0c;可以通过右键项目->添加资源字典的方式来添加一个资源字典文件…