基于注解的声明式事务

news2024/11/23 9:12:55

1.什么是事务


数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。


2.事务的特性


A:原子性(Atomicity)
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行定程中发生错误,会被回滚(Rollback) 到事务开始前的状态,就像这个事务从来没有执行过一样。
C:一致性(Consistency)
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。

如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。

如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。

I:隔离性(Isolation)
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
D:持久性(Durability)
指的是只要事务成功结束,它对数据库所做的更新就必须保存下来。即使发生系统崩溃,重新启动数据库系统后数据库还能恢复到事务成功结束时的状态。

3.编程式事务

事务功能的相关操作全部通过自己编写代码来实现。

   Connection conn = ...;
    try{
        //开启事务:关闭事务的自动提交
        conn.setAutoCommit(false);
        //核心操作
        
        //提交事务
        conn.commit();
        
    }catch(Exception e){
        //回滚事务
        conn.rollback();
        
    }finally{
        //释放数据库连接
        conn.close();
    }

编程式的实现方式存在缺陷:
        细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。
        代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。


4.声明式事务


既然事务控制的代码有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。
封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。
        好处1:提高开发效率
        好处2:消除了几余的代码
        好处3:框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题,进行了健壮性、性能等各个方面的优化。

总结:

编程式:自己写代码实现功能。

声明式:通过配置框架实现功能。

5.实现

①基于注解实现

1.配置bean文件

<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"
       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">
<!--    组件扫描-->
<context:component-scan base-package="com.yogurt.spring6.tx"></context:component-scan>
<!--    引入外部属性文件,创建数据源对象-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
<!--    创建jdbcTemplate对象,注入数据-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

</beans>

2.创建表

图书表

create table t_book(
book_id int(11) not null auto_increment comment '主键',
book_name varchar(20) default null comment '图书名称',
price int(11) default null comment '价格',
stock int(10) unsigned default null comment '库存(无符号)',
primary key (book_id))engine=innodb auto_increment=3 default charset=utf8;

用户表 

create table t_user(
user_id int(11) not null auto_increment comment '主键',
username varchar(20) default null comment '用户名',
balance int(10) unsigned default null comment '余额(无符号)',
primary key (user_id))engine=innodb auto_increment=2 default charset=utf8;

案例测试: 

买书过程(创建Controller、Service、Dao)

 

Controller

@Controller
public class BookController {

    @Autowired
    private BookService bookService;

    /**
     * 买书的方法
     * @param bookId
     * @param userId
     */
    public void buyBook(Integer bookId,Integer userId){
        //调用Service方法
        bookService.buyBook(bookId,userId);
    }
}

Service

@Service
public class BookServiceImpl implements BookService{

    @Autowired
    private BookDao bookDao;

    /**
     * 买书的方法
     * @param bookId
     * @param userId
     */
    @Override
    public void buyBook(Integer bookId, Integer userId) {
        //根据图书id查询图书价格
        Integer price = bookDao.getBookPriceByBookId(bookId);

        //更新图书库存量 -1
        bookDao.updateStock(bookId);

        //更新用户表用户余额 -图书价格
        bookDao.updateUserBalance(userId,price);

    }
}

Dao 

@Repository
public class BookDaoImpl implements BookDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 根据id查询图书价格
     * @param bookId
     * @return
     */
    @Override
    public Integer getBookPriceByBookId(Integer bookId) {
        String sql = "select price from t_book where book_id = ?";
        Integer price = jdbcTemplate.queryForObject(sql, Integer.class, bookId);
        return price;
    }

    /**
     * 更新库存信息
     * @param bookId
     */
    @Override
    public void updateStock(Integer bookId) {
        String sql = "update t_book set stock = stock -1 where book_id = ?";
        jdbcTemplate.update(sql,bookId);

    }

    /**
     * 更新用户表用户余额 -图书价格
     * @param userId
     * @param price
     */
    @Override
    public void updateUserBalance(Integer userId, Integer price) {
        String sql = "update t_user set balance = balance - ? where user_id = ?";
        jdbcTemplate.update(sql,price,userId);

    }
}

测试

@SpringJUnitConfig(locations = "classpath:bean.xml")
public class TestBookTx {

    @Autowired
    private BookController bookController;

    @Test
    public void testBuyBook(){
        bookController.buyBook(1,1);
    }

}

 案例添加事务:

开启事务的注解驱动

引入新的命名空间:

开启注解驱动: 

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>
<!--    开启事务的注解驱动
        transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
添加事务注解 (Service层)
注解标识的位置:

@Transactional标识在方法上,只能影响该方法

@Transactional标识在类上,则会影响类中所有方法 

测试(余额不足时):
@SpringJUnitConfig(locations = "classpath:bean.xml")
public class TestBookTx {

    @Autowired
    private BookController bookController;

    @Test
    public void testBuyBook(){
        bookController.buyBook(1,1);
    }

}
结果(数据库数据不改变): 

 

6.事务相关属性 

只读

@Transactional(readOnly = true)

超时(三秒未响应就超时)

@Transactional(timeout = 3)

模拟超时效果

回滚策略

@Transactional(noRollbackFor = ArithmeticException.class)

当出现此异常时,不回滚事务

隔离级别

@Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别

@Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交

@Transactional(isolation = Isolation.READ_COMMITTED)//读已提交

@Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读

@Transactional(isolation = Isolation.SERIALIZABLE)//串行化 

传播行为

在service类中有a()方法和b()方法,a()方法上有事务,b()方法上也有事务,当a(方法执行过程中调用了b()方法事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为。
共有七种传播行为:
REQUIRED:支持当前事务,如果不存在就新建一个(默认)[没有就新建,有就加入]

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行[有就加入,没有就不管了]

MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常[有就加入,没有就抛异常]
REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起[不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起]
NOT SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务[不支持事务,存在就挂起]。

NEVER:以非事务方式运行,如果有事务存在,抛出异常[不支持事务,存在就抛异常]
NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。[有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。]

全注解配置事务 

1.创建SpringConfig(代替bean文件)

@Configuration //配置类
@ComponentScan("com.yogurt.spring6.tx")
@EnableTransactionManagement //开启事务管理
public class SpringConfig {

    @Bean
    public DataSource getDateSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("Mitaowulong");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring");
        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;
    }
}

2.创建接口实现类

@Service
public class CheckoutServiceImpl implements CheckoutService{

    //注入BookService
   @Autowired
    private BookService bookService;

    //买多本书的方法
    @Transactional
    @Override
    public void checkout(Integer[] bookIds, Integer userId) {
        for(Integer bookId:bookIds){
            //调用service方法
            bookService.buyBook(bookId,userId);
        }

    }
}

3.测试

public class TestAnno {
    @Test
    public void testTxAllAnnotation(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookController accountService = applicationContext.getBean("bookController",BookController.class);
        Integer[] bookIds = {1,2};
        accountService.checkout(bookIds,1);
    }
}

 

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

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

相关文章

互联网Java工程师面试题·微服务篇·第一弹

目录 ​编辑 1、您对微服务有何了解&#xff1f; 2、微服务架构有哪些优势&#xff1f; 3、微服务有哪些特点&#xff1f; 4、设计微服务的最佳实践是什么&#xff1f; 5、微服务架构如何运作&#xff1f; 6、微服务架构的优缺点是什么&#xff1f; 7、单片&#xff0c…

【MySQL】事务(上)

文章目录 事务概念什么是事务&#xff1f;为什么要有事务&#xff1f;事务的版本支持事务的提交方式事务常见操作方式基本操作 事务概念 mysql 本身内部采用 多线程的方式&#xff0c;来实现数据存储 相关的工作 就注定对数据 有并发访问的场景 为了解决这类问题&#xff0c;就…

RestCloud AppLink已支持的数据源有哪些?

RestCloud AppLink是什么&#xff1f; 首先&#xff0c;我们需要了解RestCloud AppLink是什么&#xff0c;AppLink是一款由RestCloud公司推出的超级应用连接器。不需要开发&#xff0c;零代码&#xff0c;低成本即可快速打通数百款应用之间的数据。通过流程搭建&#xff0c;可…

【ATTCK】MITRE Caldera 简介

一、什么是Caldera caldera是一个基于MITRE ATT&CK™构建的网络安全框架。其目标是创建一种工具&#xff0c;通过提供自动化安全评估来增强网络从业者的能力&#xff0c;从而节省用户的时间、金钱和精力。为此&#xff0c;需要几个关键组件才能使 Caldera 成为行业领先的平…

在Gradio实现两个下拉框进行联动案例解读:change/click/input实践(三)

本文的代码来自ChuanhuChatGPT&#xff0c;通过拆解写得比较好的gradio项目&#xff0c;可以更快理解gradio的一些使用。 ChuanhuChatGPT整体页面效果是比较合理的&#xff1a; 1 下拉框联动效果的解读 本篇是将一个其中【对话】中的【Prompt加载】小模块抽取出来并稍稍修改…

电商平台api接口,淘宝/天猫、1688、拼多多、亚马逊等电商数据平台api接口演示案例

API简单来说是一种数据的传输方式&#xff0c;使用已经开发好的API接口可以缩短项目时间&#xff0c;减少开发成本。 比如说数据宝平台提供的实名认证API接口&#xff0c;像这种实名认证类的API接口是无法自行开发的&#xff0c;如果自行对接部委&#xff0c;能否成功不说&…

【已解决】vscode 配置C51和MDK环境配置

使用命令 gcc -v -E -x c - 看自己gcc 有没有安装好 也可以在自己的vscode中新建一个终端 gcc -v g -v 首先把自己的C51 和MDK 路径 设置好 vscode 中设置 C51 和 MDK 的路径 这是你keil 中写 51单片机和 STM32 的 如果你出现什么include 的什么波浪线&#xff0c;那估计…

力扣511. 游戏玩法分析 I

答案&#xff1a; select player_id,min(event_date) as first_login from Activity a group by player_id我最开始写的错误答案是这样的&#xff1a; select player_id,event_date as first_login from Activity a group by player_id having event_date min(event_date…

一篇揭秘Linux高性能服务epoll 的本质

导语 epoll接口是为解决Linux内核处理大量文件描述符而提出的方案。该接口属于Linux下多路I/O复用接口中select/poll的增强。其经常应用于Linux下高并发服务型程序&#xff0c;特别是在大量并发连接中只有少部分连接处于活跃下的情况 (通常是这种情况)&#xff0c;在该情况下能…

copilot 产生 python工具函数并生成单元测试

stock.py 这个文件&#xff0c;我只写了注释&#xff08;的开头&#xff09;&#xff0c;大部分注释内容和函数都是copilot # split a string and extract the environment variable from it # input can be , pathabc, pathabc;pathdef, pathabc;pathdef;pathghi # output i…

快速拉取聚水潭单据的ETL工具

聚水潭介绍 聚水潭平台则是国内较为出名的电商ERP平台&#xff0c;为企业提供了便捷的销售和管理服务&#xff0c;专注于提高交易效率&#xff0c;但是如何将数据快速同步到其他系统一直是很多企业的痛点。 ETLCloud数据集成平台提供了丰富的数据分析工具和算法模型&#xff…

Oracle 账户被锁:the account is locked 解决方法

Oracle 账户被锁&#xff1a;the account is locked 解决方法 连接Oracle数据库时报错账户已锁定错误 解决方法一&#xff1a;命令行模式&#xff1a; 步骤一&#xff1a; WinR打开命令行输入&#xff1a;sqlplus 使用system或sys账户以管理员身份登录&#xff0c;口令即安装…

MySQL如何查找删除重复行?

如何查找重复行 第一步是定义什么样的行才是重复行。多数情况下很简单&#xff1a;它们某几列具有相同的值。本例采用这种定义&#xff0c;或许你对“重复”的定义得很复杂&#xff0c;你需要对sql做些修改。本例要用到的数据样本&#xff1a; create table test(id int not …

学用 DevChat 的 VSCode 插件,体验AI智能编程工具 (一)

简单说DevChat是一个辅助编程的智能工具&#xff0c;它可以通过自然语言对话的方式与开发者进行交流&#xff0c;帮助开发者更高效地完成编程任务。 有了人工智能工具&#xff0c;编程进入一个新天地。 闻名已久&#xff0c;不若体验一下。 一.准备工作 1.运行环境. A. p…

MS512非接触式读卡器 IC

MS512 是一款应用于 13.56MHz 非接触式通信中的高集 成度读写卡芯片。它利用了先进的调制和解调技术&#xff0c;完全集 成了在 13.56MHz 下的各种非接触式通信方式和协议。 主要特点  高度集成的解调和解码模拟电路  采用少量外部器件&#xff0c;即可将输出驱动级接…

如何使用群晖虚拟机部署本地网页文件实现公网远程访问?

文章目录 前言1. 安装网页运行环境1.1 安装php1.2 安装webstation 2. 下载网页源码文件2.1 访问网站地址并下载压缩包2.2 解压并上传至群辉NAS 3. 配置webstation3.1 配置网页服务3.2 配置网络门户 4. 局域网访问静态网页配置成功5. 使用cpolar发布静态网页&#xff0c;实现公网…

本地PHP搭建简单Imagewheel私人云图床,在外远程访问——“cpolar内网穿透”

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

互联网金融P2P主业务场景自动化测试

互联网金融P2P行业&#xff0c;近三年来发展迅速&#xff0c;如火如荼。 据不完全统计&#xff0c;全国有3000的企业。 “互联网”企业&#xff0c;几乎每天都会碰到一些奇奇怪怪的bug&#xff0c;作为在互联网企业工作的测试人员&#xff0c;风险和压力都巨大。那么我们如何降…

学习c#的第九天

目录 C# 可空类型&#xff08;Nullable&#xff09; C# 可空类型&#xff08;Nullable&#xff09; Null 合并运算符&#xff08; ?? &#xff09; C# 数组&#xff08;Array&#xff09; 一维数组 声明及初始化赋值数组 多维数组 声明和初始化多维数组 访问和操作多…