当前位置: 首页 > news >正文

Spring框架 - 声明式事务管理

目录

  • Spring框架事务管理
    • Spring声明式事务
    • 相关的类和API
  • Spring框架声明式事务管理
    • 声明式事务管理
    • 配置文件形式
      • Bean管理的元素属性
      • 实操案例
    • 半注解形式(配置文件 + 注解)
      • 常用的注解
      • 实操案例
    • 全注解形式
      • 实操案例

Spring框架事务管理

Spring声明式事务

声明式事务是Spring框架提供的一种通过配置而非编程代码来管理事务的方式。

相关的类和API

  1. PlatformTransactionManager接口:平台事务管理器

    • 该接口根据不同的持久层框架,选择不同的具体实现类:
    • 接口方法:
      • void commit(TransactionStatus status)
      • void rollback(TransactionStatus status)
      • 使用Spring框架的JDBC模板或者MyBatis框架,选择DataSourceTransactionManager实现类
      • 使用Hibernate框架,选择HibernateTransactionManager实现类
  2. TransactionDefinition接口,事务定义信息接口

    • 定义了事务隔离级别
    • 定义了事务传播行为

Spring框架声明式事务管理

声明式事务管理

有三种形式:

  1. 配置文件形式
  2. 半注解形式(配置文件 + 注解)
  3. 全注解形式(注解)

配置文件形式

Bean管理的元素属性

  1. <tx:advice>:事务通知配置
    • id:事务通知标识符,用于其它地方引用
    • transaction-manager:指定事务管理器Bean的id叫什么
    • <tx:attributes>:定义方法级别的事务属性
    • <tx:method>:为匹配的方法指定详细的事务行为规则
    • name:匹配XX的方法
    • isolation:隔离级别
    • read-only
  2. <aop:config>:AOP通知配置
    • <aop:advisor>:系统通知
    • advice-ref:引用上面的事务
    • pointcut:定义切入点表达式

<aop:advisor><aop:aspect> 的区别:

特性<aop:advisor><aop:aspect>
用途系统级通知自定义业务通知
通知类型通常使用Around通知支持5种通知
配置方式引用外部定义的Advice在aspect内部定义通知方法
灵活性相对固定更灵活,可自定义逻辑

实操案例

  1. 创建maven Java项目
  2. 引入依赖
    <!-- Maven中配置Java版本 -->
    <properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target>
    </properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><!--有单元测试的环境,Spring5版本,Junit4.12版本--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mysql驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- Spring整合Junit测试的jar包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope></dependency><!-- AOP联盟 --><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!-- Spring Aspects --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version></dependency><!-- aspectj --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.2.RELEASE</version></dependency>
    </dependencies>
    
  3. 创建实体类:Account类
    • 添加id、name、money这三个成员变量(字段)
    • 获取它们的getter/setter方法
  4. 创建持久层的接口类和实现类:AccountDao类和AccountDaoImpl类
    package com.qcby.dao;public interface AccountDao {/*** 转账* @param name  转账人* @param money 金额*/public void outMoney(String name, Double money);/*** 收账* @param name  收账人* @param money 金额*/public void inMoney(String name, Double money);
    }
    
    package com.qcby.dao.impl;import com.qcby.dao.AccountDao;
    import org.springframework.jdbc.core.JdbcTemplate;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic void outMoney(String name, Double money) {//编写sql语句String sql = "update account set money = money - ? where name = ?";jdbcTemplate.update(sql, money, name);}@Overridepublic void inMoney(String name, Double money) {String sql = "update account set money = money + ? where name = ?";jdbcTemplate.update(sql, money, name);}
    }
    
  5. 创建业务层的接口来和实现类:AccountService类和AccountServiceImpl类
    package com.qcby.service;public interface AccountService {/**** @param out   转账* @param in    收账* @param money 金额*/public void pay(String out, String in, Double money);
    }
    
    package com.qcby.service.impl;import com.qcby.dao.AccountDao;
    import com.qcby.service.AccountService;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/**** @param out   转账* @param in    收账* @param money 金额*/@Overridepublic void pay(String out, String in, Double money) {accountDao.outMoney(out,money);accountDao.inMoney(in,money);}
    }
    
  6. 编写属性文件:jdbc.properties
    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql:///spring_db
    jdbc.username=username // 你的用户名
    jdbc.password=userpassword // 你的密码
    
  7. 编写配置文件:applicationContext.xml
    • 加载属性文件,并配置参数
    • 配置平台事务管理器
    • 配置事务通知(有Spring提供的切面类)
    • 配置AOP增强
    • 配置jdbc模板
    • 配置Service
    • 配置dao
    <?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:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"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/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--配置文件形式--><!--使用标签方式--><!--加载属性文件--><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置平台事务管理器--><bean id="tran" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--配置事务的通知(由Spring提供的切面类)--><tx:advice id="txAdvice" transaction-manager="tran"><tx:attributes><!--对pay进行增强,设置隔离级别,传播行为,超时时间--><tx:method name="pay" isolation="DEFAULT"/><tx:method name="find*" read-only="true"></tx:method></tx:attributes></tx:advice><!--配置AOP增强--><aop:config><!--Spring框架提供系统通知,使用advisor标签--><aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.pay(..))"></aop:advisor></aop:config><!--配置jdbc模板--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!--配置Service--><bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property></bean><!--配置Dao--><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate"></property></bean>
    </beans>
    
  8. 创建测试类:AccountTest类
    package com.qcby.text;import com.qcby.service.AccountService;
    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;/*** IOC:配置文件形式* JDBC模板,配置文件形式 + 属性文件* 声明式事务:配置文件形式(Spring框架提供AOP)*/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AccountTest {@Autowiredpublic AccountService accountService;@Testpublic void run(){accountService.pay("美羊羊","沸羊羊",100.0);}
    }
    

半注解形式(配置文件 + 注解)

常用的注解

  • @Transactional()注解:将一个方法或类标记为需要事务性执行
    • 也就是说,在方法上添加了这个注解,Spring会在这个方法上开始执行前自动开启一个数据库事务,方法完毕后提交事务,出现异常回滚事务。
  • isolation属性:设置事务隔离级别
  • @EnableAspectJAutoProxy注解:开启事务注解
  • @PropertySource("classpath:jdbc.properties")注释:读取属性文件

实操案例

  1. 前三步与上面配置文件形式一样
  2. 持久层种的实现类,加上注解
    @Repository("accountDao2")
    public class AccountDaoImpl2 implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;// ……其它代码与上面一致
    }
    
  3. 业务层种的实现类,加上注解
    @Service("accountService2")
    // 设置事务级别
    @Transactional(isolation = Isolation.DEFAULT)
    public class AccountServiceImpl2 implements AccountService{@Autowired@Qualifier("accountDao2")private AccountDao accountDao;// ……其它代码与上面一致
    }
    
  4. 属性文件内容不变
  5. 配置文件内容有修改:applicationContext2.xml
    • 去掉配置Service、配置Dao、配置AOP增强的Bean管理代码,修改为开启注解扫描
    • 去掉配置事务的通知(由Spring提供的切面类)的相关代码,修改为开启事务注解支持
    <?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:context="http://www.springframework.org/schema/context"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/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--配置文件 + 注解--><!--开启注解扫描--><context:component-scan base-package="com.qcby"><!-- 排除标注了@Configuration的类 --><context:exclude-filter type="annotation"expression="org.springframework.context.annotation.Configuration"/></context:component-scan><!--标签方式--><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!--加载属性文件--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--配置平台事务管理--><bean id="tean" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--配置JDBC模板--><bean id="jdebTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!--开启事务注解支持--><tx:annotation-driven transaction-manager="tean"></tx:annotation-driven>
    </beans>
    
  6. 创建测试类:AccountTest2类
    package com.qcby.text;import com.qcby.service.AccountService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** IOC:配置文件形式 + 注解* JDBC模板,配置文件形式 + 属性文件* 声明式事务:配置文件形式 + 注解*/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext2.xml")
    public class AccountTest2 {@Autowired@Qualifier("accountService2")public AccountService accountService;@Testpublic void run(){accountService.pay("美羊羊","沸羊羊",100.0);}
    }
    

全注解形式

实操案例

  1. 前3步与上面半注解形式一致
  2. 不在需要属性文件和配置文件,只需要创建配置类:SpringConfig类
    • 配置数据库连接池
    • 创建模板对象
    • 创建平台事务管理对象
    package com.qcby.tools;import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.transaction.PlatformTransactionManager;import javax.annotation.Resource;
    import javax.sql.DataSource;@Configuration
    @ComponentScan("com.qcby")
    // 开启事务注解
    @EnableAspectJAutoProxy
    public class SpringConfig {/*** 连接数据库* @return* @throws Exception*/@Bean("dataSource")public DataSource dataSource() throws Exception{// 创建连接池对象,Spring框架内置了连接池对象DriverManagerDataSource ds = new DriverManagerDataSource();// 设置4个参数ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///spring_db");ds.setUsername("root");ds.setPassword("root");return ds;}/*** 创建模板对象* @param dataSource* @return*/@Resource(name = "dataSource") // 不仅可以作用在属性上,也可以作用方法上@Bean("jdbcTemplate") // 把JdbcTemplate保存到IOC容器中public JdbcTemplate createJdbcTemplate(DataSource dataSource){JdbcTemplate template = new JdbcTemplate(dataSource);return template;}/*** 创建平台事务管理器对象* @param dataSource* @return*/@Resource(name = "dataSource")@Bean("manager")public PlatformTransactionManager createTransactionManager(DataSource dataSource){DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);return manager;}
    }
    
  3. 创建测试类:AccountTest3类
    package com.qcby.text;import com.qcby.service.AccountService;
    import com.qcby.tools.SpringConfig;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** IOC全注解:注解类* JDBC模板全注解,注解类* 声明式事务:注解类*/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {SpringConfig.class})
    public class AccountTest3 {@Autowired@Qualifier("accountService3")public AccountService accountService;@Testpublic void run(){accountService.pay("美羊羊","沸羊羊",100.0);}
    }
    
http://www.dtcms.com/a/600886.html

相关文章:

  • html淘宝店铺网站模板辽宁移动网站
  • 微硕WST3404高性能MOSFET,革新汽车雨刮控制系统
  • LeetCode(python)——53.最大子数组的和
  • 其中包含了三种排序算法的注释版本(冒泡排序、选择排序、插入排序),但当前只实现了数组的输入和输出功能。
  • macOS安装SDKMAN
  • LeetCode热题100--78. 子集
  • 攻击链重构的技术框架
  • 商务网站的特点做外贸的人经常逛的网站
  • 网站绑定两个域名怎么做跳转贵阳网络推广公司哪家强
  • 关于sqlite
  • 【C语言】深入理解指针(三)
  • BHYRA:当金融的信任,开始由收益来证明
  • 安装paddle_ocr踩坑(使用PP-OCRv5_server_rec)
  • ClickHouse查看数据库、表、列等元数据信息
  • 场外衍生品系统架构解密:TRS收益互换与场外个股期权的技术实现与业务创新
  • PQ:软件的UX - 快速分析并提议改进
  • MoonBit Pearls Vol.15: 使用 MoonBit 和 Wassette 构建安全的 WebAssembly 工具
  • 旅游机票网站建设2022年时事新闻摘抄
  • 【Linux网络】基于UDP的Socket编程,实现简单聊天室
  • IntelliJ IDEA 快捷键全解析与高效使用指南
  • openGauss 实战手册:gsql 常用命令、认证配置与运维工具全解
  • 如何入门Appium-移动端自动化测试框架?
  • 解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
  • 【ZeroRange WebRTC】KVS WebRTC 示例中的 HTTP 通信安全说明
  • 软件测试之单元测试知识总结
  • 如何更改asp网站自定义产品顺序网站推广优化建设方案
  • 手机网站优点linux服务器wordpress
  • HPC性能新纪元!AWS Hpc7g实例: Graviton3E芯片开启200Gbps超算之旅
  • LeetCode 422 - 有效的单词方块
  • windows docker 配置镜像