基于注解的声明式事务

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);
    }
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国际阿里云:提高CDN缓存命中率教程!!!

CDN缓存命中率低会导致源站压力大&#xff0c;静态资源访问效率低。您可以根据导致CDN缓存命中率低的具体原因&#xff0c;选择对应的优化策略来提高CDN的缓存命中率。 背景信息 CDN通过将静态资源缓存在CDN节点上实现资源访问加速。当客户端访问某资源时&#xff0c;如果CDN节…

腾讯待办停运后怎么办呢?导出的ics文件怎么打开查看

待办类工具在日常工作中的应用是比较广泛的&#xff0c;很多人会选择使用待办软件记录备忘事项&#xff0c;其中一些提醒类的工具是比较广泛使用的。腾讯待办属于一款待办事项和日程管理工具&#xff0c;它通常是以微信小程序的形式&#xff0c;为大家提供时间管理规划&#xf…

应急响应练习2

目录 1. 请提交攻击者的ip与系统版本 2. 攻击者通过某个组件漏洞获得服务器权限&#xff0c;请提交该组件的名称 3. 请提交攻击者首次攻击成功的时间 4. 请提交攻击者上传的webshell文件绝对路径 5. 请提交攻击者使用的webshell管理工具 6. 攻击者进一步留下的免杀的webs…

AGV与AMR的区别

如今&#xff0c;市面上最受关注的两类工业移动机器人分别是AGV和AMR。但大众对于两者的区别还是不甚了解&#xff0c;因此小编将通过这篇文章为大家详细解释。 一、概念阐述 【AGV 】 AGV (Automated Guided Vehicle) 即自动导引运输车&#xff0c;可指基于各种定位导航技术…

2023数据结构期中测验-2023秋-计算机+未来网络专业

数据结构期中测验 选择题函数题6-1 求链式表的表长6-2 逆序数据建立链表6-3 删除单链表偶数节点6-4 求二叉树高度6-5 先序输出叶结点 为了防止不自觉的朝答案看去&#xff0c;特意用了明黄色字体&#xff0c;如下查看答案&#xff1a; 选择题 2-1 下述程序段的时间复杂度为&am…

独立站商品信息是怎么获取的呢

独立站商品信息的获取主要通过以下几种方式&#xff1a; 人工收集&#xff1a;卖家可以通过在各个电商平台、网站等渠道进行手动搜索和收集商品信息&#xff0c;包括商品名称、价格、描述、图片等&#xff0c;然后将其导入到自己的独立站中。使用采集工具&#xff1a;目前市面…

暖手宝上架亚马逊美国站UL499报告测试标准要求

暖手宝是运用物理及化学原理研制的自动取暖保健用品。该产品以其自动生热&#xff0c;有趣&#xff0c;实用等新颖独特的优势&#xff0c;深受欢迎——暖手宝具有自动取暖&#xff0c;理疗保健等多种功能。只要插上电源等上10分钟左右就能发热&#xff0c;最后一种是通过锂电池…

arcgis--消除坐标系信息的两种方法

方法一&#xff1a;在【目录】中右击待修改数据&#xff0c;选择【属性】&#xff0c;选择【XY坐标】选项卡&#xff0c;点击清楚按钮。 方法二&#xff1a;在【数据管理工具】-【投影与变换】-【定义投影】中清楚坐标系信息。如下&#xff1a;

如何用Python实现图像拼接画(把一堆小图拼成大图)

诸神缄默不语-个人CSDN博文目录 在这里的图像拼接画指的是一张大图由很多小图组成&#xff0c;效果就像这样&#xff1a; 原理&#xff1a;将大图拆成很多小块&#xff0c;每一块计算平均颜色&#xff0c;用平均颜色最相近的小图来替代&#xff0c;就可以。 直接遍历就可以&…

FFmpeg开发简介1

适逢FFmpeg6.1发布&#xff0c;准备深入学习下FFmpeg&#xff0c;将会写下系列学习记录。 在此列出主要学习资料&#xff0c;后续再不列&#xff0c;感谢这些大神的探路和分享&#xff0c;特别是雷神&#xff0c;致敬&#xff01; 《FFmpeg从入门到精通》 《深入理解FFmpeg》 …

使用Nginx和uwsgi在自己的服务器上部署python的flask项目

Nginx 是一个高性能的 HTTP 和反向代理服务。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务器中表现较好。 Nginx 专为性能优化而开发&#xff0c;性能是其最重要的考量指标&#xff0c;实现上非常注重效率&#xff0c;能经受…

Structure-Inferred Bi-level Model for Underwater Image Enhancement论文小结

背景 随着水下机器人的发展&#xff0c;水下图像增强引起了计算机视觉界越来越多的关注。然而&#xff0c;由于光线在水中传播时会被散射和吸收&#xff0c;水下捕捉到的图像往往存在偏色和能见度低的问题。现有的方法依赖于特定的先验知识和训练数据&#xff0c;在缺乏结构信…

无人地磅称重系统|自助过磅 料仓联动 自助卸料

上海思伟无人地磅系统 自助过磅、 自助卸料 、料仓联动 智能、省人、安全 无人监管过磅 对地磅及其相关的所有硬件进行配置和管理&#xff1b; 支持红外、道闸、车牌识别、AI分析、拍照存档、LED语音播报一体机等设备&#xff1b; 实现稳定可靠的无人监管称重功能&#xf…

安防监控系统EasyCVR v3.4.0版本首页界面更新调整功能大汇总

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、…

C# 智慧医学实验室LIS系统源码,支持预制条码和即时打印条码;支持单工/双工数据采集;支持TAT监测与分析;具备检验智能审核功能,支持自定义多级审核规则

C#医院检验信息管理系统源码&#xff0c;智慧医学实验室LIS系统源码&#xff0c;云LIS系统源码 医院检验信息管理系统&#xff0c;利用计算机网络技术、数据存储技术、快速处理技术&#xff0c;对检验科进行全方位信息化管理&#xff0c;使检验科达到自动化运行&#xff0c;信息…

vscode使用flake8设置单行最长字符限制设置失败的问题

vscode使用flake8设置单行最长字符限制设置失败的问题 问题描述解决方案 问题描述 如图所示&#xff0c;使用flake8单行字数过长&#xff0c;就会有有红色底的波浪线 一般情况下很多教程都会让你在setting.json里面设置 但是我打开我的setting.json&#xff0c;发现我已经进…

体验家XMPlus收购NPSMeter,稳固体验管理行业“领头羊”地位

2023年9月30日&#xff0c;体验家XMPlus&#xff08;以下简称“体验家”&#xff09;成功完成了对NPSMeter的收购。此次收购是中国客户体验管理&#xff08;CEM&#xff09;赛道进入快速发展以来的首单收购&#xff0c;标志着体验家在CEM领域的进一步扩张&#xff0c;旨在继续完…

智慧工地管理云平台源码,Spring Cloud +Vue+UniApp

智慧工地源码 智慧工地云平台源码 智慧建筑源码支持私有化部署&#xff0c;提供SaaS硬件设备运维全套服务。 互联网建筑工地&#xff0c;是将互联网的理念和技术引入建筑工地&#xff0c;从施工现场源头抓起&#xff0c;最大程度的收集人员、安全、环境、材料等关键业务数据&am…

【教3妹学编程-算法题】给小朋友们分糖果 II

3妹&#xff1a;1 8得8&#xff0c;2 816&#xff0c; 3 8妇女节… 2哥 : 3妹&#xff0c;在干嘛呢 3妹&#xff1a;双11不是过了嘛&#xff0c; 我看看我这个双十一买了多少钱&#xff0c; 省了多少钱。 2哥 : 我可是一分钱没买。 3妹&#xff1a;我买了不少东西&#xff0c; …

天津火爆python培训机构从哪里入手?

Python不仅被应用在职场办公中&#xff0c;还被大型互联网公司应用于大型后端开发&#xff0c;随着大数据领域的高速发展&#xff0c;这门高效的编程语言逐渐成为处理数据的最佳编程语言之一。 Python培训班优势 系统性学习&#xff1a;Python培训班会提供结构化的课程体系&a…