Spring:事务(tx)

news2024/12/25 9:00:39

1. 简介

2b734fb75f5c45db9eb1a7aa9a185320.png

spring对jdbc进行封装,简化对数据库的操作

 2. HelloWorld

1. 搭建模块

2.加入依赖

<dependencies>
    <!--spring jdbc  Spring 持久化层支持jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.2</version>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    <!-- 数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.15</version>
    </dependency>
</dependencies>

 3.创建jdbc.properties文件

jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/study?characterEncoding=utf8&useSSL=false
jdbc.driver=com.mysql.cj.jdbc.Driver

4.配置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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:component-scan base-package="com.itgyl.tx"></context:component-scan>

    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置 JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 装配数据源 -->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--
        开启事务的注解驱动
        通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
    -->
    <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

实现CURD操作

 查

/***
 * queryForObject方法会将查询的单个对象进行返回
 * query方法会将查询的结果存入集合在将集合进行返回
 * 三个参数:
 * 参数一:执行的sql语句
 * 参数二:通过该方法可以将实例化对象创建出来,并将数据库中查询的数据存入该实例化对象中
 * 参数三以及之后的参数(非必要,如有占位符即需要带上):都是查询语句的条件判断参数
 */
@Component
@SpringJUnitConfig(locations = "classpath:beans.xml")
public class JdbcTemplateTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    
    @Test
    public void testQuery() {
        
        //查询返回单个对象
        String sql = "select * from t_emp where id = ?";
        Emp emp = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Emp.class), 3);
        System.out.println(emp);

    }
}
//查询返回单个值
        String sql = "select count(*) from t_emp";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println("总数为:" + count);
//查询返回所有数据
        String sql = "select * from t_emp";
        List<Emp> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Emp.class));
        for (Emp emp : list) {
            System.out.println(emp);
        }

//添加功能
        String sql = "insert into t_emp (name, age, sex) value (?, ?, ?)";
        int result = jdbcTemplate.update(sql, "东方不败", 19, "未知");

 改

 String sql =" update t_emp set name =  ? where name = ?";
        int result = jdbcTemplate.update(sql, "牛逼", "zhangsan");

String sql = "delete from t_emp where name = ?";
        int result = jdbcTemplate.update(sql, "牛逼");

 3. 事务

事务基本概念

 事务详情跳转链接

声明式事务

既然事务控制的代码有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。

封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。

* 好处1:提高开发效率
* 好处2:消除了冗余的代码
* 好处3:框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题,进行了健壮性、性能等各个方面的优化

基于注解的声明式事务

完成简单的图书出售事务

配置tx命名空间

<?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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

 开启事务注解驱动

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

<!--
    开启事务的注解驱动
    通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
<tx:annotation-driven transaction-manager="transactionManager" />

@Transaction注解

/***
 * 注解@Transactional及添加事务功能
 * 在类上面添加该注解则会影响类的所有方法,即所有方法都添加事务的功能
 * 在方法上面添加该注解则单影响该方法,即当前有注解的方法添加事务功能
 *      readOnly即设置只读功能,无法做修改删除插入操作
 *      timeout设置超时功能,当超过指定时机还未执行完毕则自动进行事务回滚
 *      noRollbackFor即设置不回滚操作,当满足里面的条件即使是报错也不回滚
 *      isolation即设置事务的隔离级别
 *      propagation设置事务的传播行为
 */
@Repository
public class BookDaoImp implements BookDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //@Transactional(readOnly = true)
    //@Transactional(timeout = 3)
    //@Transactional(noRollbackFor = ArithmeticException.class)
    //@Transactional(isolation = Isolation.DEFAULT)
    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Transactional
    @Override
    public boolean buyBook(Integer bookId, Integer userId) {
        //完成一个事务

        //TODO 模拟超时场景
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //1.查询库存
        String sqlBookSelect = "select price from t_book where book_id = ?";
        Integer price = jdbcTemplate.queryForObject(sqlBookSelect, Integer.class, bookId);

        //2.用户购买库存减少
        String sqlBook = "update t_book set stock = stock - 1 where book_id = ?";
        int rows = jdbcTemplate.update(sqlBook, userId);

        //3.用户扣款
        String sqlUser = "update t_user set balance = balance - 50 where  user_id = ?";
        int rows2 = jdbcTemplate.update(sqlUser, userId);

        //int j = 1 / 0;
        return rows2 == rows;
    }
}
@Service
public class BookServiceImp implements BookService{
    @Autowired
    private BookDao bookDao;

    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean buyBook(Integer bookId, Integer userId) {
        return bookDao.buyBook(bookId, userId);
    }
}

 

只读

对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。

超时

事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。

概括来说就是一句话:超时回滚,释放资源。

 回滚策略

声明式事务默认只针对运行时异常回滚,编译时异常不回滚。

可以通过@Transactional中相关属性设置回滚策略

* rollbackFor属性:需要设置一个Class类型的对象
  
* rollbackForClassName属性:需要设置一个字符串类型的全类名
  
* noRollbackFor属性:需要设置一个Class类型的对象
  
* rollbackFor属性:需要设置一个字符串类型的全类名

 隔离级别

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

隔离级别一共有四种:

* 读未提交:READ UNCOMMITTED允许Transaction01读取Transaction02未提交的修改。
  
* 读已提交:READ COMMITTED、要求Transaction01只能读取Transaction02已提交的修改。
  
* 可重复读:REPEATABLE READ确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
  
* 串行化:SERIALIZABLE确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

传播行为

* REQUIRED:支持当前事务,如果不存在就新建一个(默认)**【没有就新建,有就加入】**
* SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行**【有就加入,没有就不管了】**
* MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
* REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】**
* NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
* NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
* NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。**【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。】 

 全注解配置事务

//基于全注解管理事务
@Configuration
@ComponentScan("com.itgyl") //开启组件扫描
@EnableTransactionManagement //开启事务管理等同于<tx:annotation-driven transaction-manager="transactionManager" />
public class SpringConfig {

    //设置连接数据库
    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/study?characterEncoding=utf8&useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    //
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

基于XML的声明式事务

<aop:config>
    <!-- 配置事务通知和切入点表达式 -->
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.atguigu.spring.tx.xml.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- tx:advice标签:配置事务通知 -->
<!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
<!-- transaction-manager属性:关联事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- tx:method标签:配置具体的事务方法 -->
        <!-- name属性:指定方法名,可以使用星号代表多个字符 -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="query*" read-only="true"/>
        <tx:method name="find*" read-only="true"/>

        <!-- read-only属性:设置只读属性 -->
        <!-- rollback-for属性:设置回滚的异常 -->
        <!-- no-rollback-for属性:设置不回滚的异常 -->
        <!-- isolation属性:设置事务的隔离级别 -->
        <!-- timeout属性:设置事务的超时属性 -->
        <!-- propagation属性:设置事务的传播行为 -->
        <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
    </tx:attributes>
</tx:advice>

 

 

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

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

相关文章

基于ERNIE Bot SDK开发智趣灯谜会游戏

项目背景 猜灯谜是中国传统节日元宵节中一种深受人们喜爱的民间游戏&#xff0c;它集趣味性、知识性和艺术性于一体&#xff0c;是中华文化的重要组成部分。猜灯谜&#xff0c;顾名思义&#xff0c;就是通过解读谜面来猜测谜底&#xff0c;谜底通常是各种物品、现象或概念。 猜…

驱动未来:IT行业的现状与发展趋势

前言 随着技术的不断进步&#xff0c;IT行业已成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链&#xff0c;这些技术正在重塑我们的生活和工作方式。本文将探讨IT行业的现状和未来发展趋势&#xff0c;并邀请行业领袖、技术专家和…

JAVA面试题大全(十八)

1、说一下 jvm 的主要组成部分&#xff1f;及其作用&#xff1f; 类加载器&#xff08;ClassLoader&#xff09;运行时数据区&#xff08;Runtime Data Area&#xff09;执行引擎&#xff08;Execution Engine&#xff09;本地库接口&#xff08;Native Interface&#xff09;…

如何本地 Debug React 源码

日常开发过程中&#xff0c;有时 debug react 源代码进行问题排查。一种方案是直接把通过 html 引入进来&#xff0c;另外一种是编译并通过 yarn 链接到项目中&#xff0c;本地将介绍如何通过这两种方法进行代码 Debug。 页面引入源代码方式 这种方式比较简单&#xff0c;直接…

【网络协议】一文带你搞懂Tcp和Udp(万字详解)

文章目录 前言一、端口号端口号的范围划分 二、UDP和TCP2.1 UDP2.2 UDP的特点 三、TCP四、TCP的十个核心机制1.确认应答机制2.超时重传3.连接管理--三次握手 四次挥手**三次握手**四次挥手 4.滑动窗口5.流量控制6.阻塞控制7.延迟应答8.捎带应答9.粘包问题10.异常情况 前言 再上…

LabVIEW中实现Trio控制器的以太网通讯

在LabVIEW中实现与Trio控制器的以太网通讯&#xff0c;可以通过使用TCP/IP协议来完成。这种方法包括配置Trio控制器的网络设置、使用LabVIEW中的TCP/IP函数库进行数据传输和接收&#xff0c;以及处理通讯中的错误和数据解析。本文将详细说明实现步骤&#xff0c;包括配置、编程…

为什么选择CleanMyMac软件呢?推荐理由

你是否曾经遇到过这样的问题&#xff1a;电脑运行缓慢&#xff0c;存储空间不足&#xff0c;不知道如何清理垃圾文件&#xff1f;别担心&#xff0c;我们为你找到了解决方案——CleanMyMac软件。这款强大的工具可以帮助你轻松解决这些问题&#xff0c;让你的电脑焕然一新&#…

【vue-4】遍历数组或对象v-for

1、遍历数组 <ul><li v-for"(value,index) in web.number">index>{{index}}:value>{{value}}</li> </ul> 知识点&#xff1a; <ul>标签定义无序列表 举例&#xff1a; <ul><li>Coffee</li><li>Tea…

【Mac】Ulysses for Mac(优秀的markdown写作软件) v34.3中文版安装教程

软件介绍 哪款markdown写作软件最好用&#xff1f;小编推荐您使用尤利西斯&#xff1a;Ulysses mac版&#xff01;这是mac上一款优秀的markdown写作工具。Ulysses mac版具备全新的Soulmen写作坏境&#xff0c;采用了革命性的功能增强&#xff0c;结合了最好的部分最小标记&…

项目开发-若依框架

文章目录 框架下载及运行项目学习需求修改左侧菜单栏增加标签-项目信息搭建过程问题解决 后续需要看的内容 框架下载及运行 下载安装&#xff1a; https://blog.csdn.net/anxiaoxiao61/article/details/122505963 https://blog.csdn.net/m0_67376124/article/details/12761749…

ARTS Week 31

Algorithm 本周的算法题为 1556. 千位分隔数 给你一个整数 n&#xff0c;请你每隔三位添加点&#xff08;即 "." 符号&#xff09;作为千位分隔符&#xff0c;并将结果以字符串格式返回。 示例 1&#xff1a;输入&#xff1a;n 123456789输出&#xff1a;"123.…

D2Admin:企业中后台产品前端集成方案的探索与实践

D2Admin&#xff1a;企业中后台产品前端集成方案的探索与实践 摘要&#xff1a;随着企业信息化建设的不断深入&#xff0c;中后台管理系统的前端技术选型与集成方案成为了关键。D2Admin作为一款完全开源免费的前端集成方案&#xff0c;通过采用最新的前端技术栈&#xff0c;提…

基于jeecgboot-vue3的Flowable增加表单功能(二)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 接上一节 6、增加一个types.ts 类型 export interface FormForm {id: number | string | undefined;formName: string;formContent?: string;remark: string; } 7、api增加一个getForm…

AI大模型日报#0528:Greg专访 | 为什么OpenAI最先做出GPT-4、xAI获60亿美元融资、李飞飞经典对话Hinton

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-34B&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff0…

Android USB调试模式下自动上下滑动(Go实现)

简介 有的时候要对手机UI界面进行滑动测试&#xff0c; 手动或许太消耗时间&#xff0c; 理由Android USB调试模式对UI进行上下滑动测试。 adb指令 使用adb --help 可以查看所有的adb支持指令, 但这里我们只需要上下, 使用到的指令&#xff1a; adb devices #列举所有设备 ad…

Git简单理解

Git 概述 Git 是一个免费的开源的&#xff0c;分布式版本控制系统&#xff0c;可以快速高效的处理从小型到大型的各种项目 Git占地面积小&#xff0c;性能极快&#xff0c;具有廉价的本地库&#xff0c;方便的暂存区和多个工作流分支等特性 版本控制 版本控制是一种记录文件…

gitea的git库备份与恢复

文章目录 gitea库的备份与恢复概述笔记实验环境更新git for windows更新 TortoiseGit备份已经存在的gitea的git库目录使用gitea本身来备份所有git库目录将gitea库恢复到新目录m1m2m3启动gitea - 此时已经恢复完成FETCH_HEAD 中有硬写位置再查一下app.ini, 是否改漏了。m1m2 总结…

操作系统 - 文件管理

文件管理 考纲内容 文件 文件的基本概念&#xff1b;文件元数据和索引节点(inode) 文件的操作&#xff1a;建立&#xff0c;删除&#xff0c;打开&#xff0c;关闭&#xff0c;读&#xff0c;写 文件的保护&#xff1b;文件的逻辑结构&#xff1b;文件的物理结构目录 目录的基…

SpringBoot启动流程分析之ApplicationEnvironmentPreparedEvent事件发布(四)

SpringBoot启动流程分析之ApplicationEnvironmentPreparedEvent事件发布&#xff08;四&#xff09; 目录&#xff1a; 文章目录 SpringBoot启动流程分析之ApplicationEnvironmentPreparedEvent事件发布&#xff08;四&#xff09;构建环境1、创建ConfigurableEnvironment对象…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-24.3,4 SPI驱动实验-I.MX6U SPI 寄存器

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…