Spring-声明式事务实例(有详细注释)

前提知识

Spring-IOC容器注解方式使用icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/136784799?spm=1001.2014.3001.5501
切点表达式icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/136782885?spm=1001.2014.3001.5501

案例 

1.创建项目

2.导入依赖

<dependency>                                       
    <groupId>mysql</groupId>                       
    <artifactId>mysql-connector-java</artifactId>  
    <version>8.0.25</version>                      
</dependency>                                      
<dependency>                                       
    <groupId>com.alibaba</groupId>                 
    <artifactId>druid</artifactId>                 
    <version>1.2.8</version>                       
</dependency>                                      
<!-- spring-jdbc -->                               
<dependency>                                       
    <groupId>org.springframework</groupId>         
    <artifactId>spring-jdbc</artifactId>           
    <version>6.0.6</version>                       
</dependency>                                      
                                                   
<dependency>                                       
    <groupId>org.springframework</groupId>         
    <artifactId>spring-tx</artifactId>             
    <version>6.0.6</version>                       
</dependency>                                      

3.数据库准备 

-- ----------------------------
-- Table structure for students
-- ----------------------------
DROP TABLE IF EXISTS `students`;
CREATE TABLE `students`  (
  `id` int NOT NULL,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `gender` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `age` int NULL DEFAULT NULL,
  `class` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Records of students
-- ----------------------------
INSERT INTO `students` VALUES (1, '喜羊羊', '男', 18, '高中一班');
INSERT INTO `students` VALUES (2, '美羊羊', '女', 19, '高中二班');
INSERT INTO `students` VALUES (3, '懒羊羊', '男', 18, '高中一班');
INSERT INTO `students` VALUES (4, '沸羊羊', '男', 18, '高中三班');
INSERT INTO `students` VALUES (5, '暖羊羊', '女', 19, '高中二班');
INSERT INTO `students` VALUES (6, '软绵绵', '男', 60, '高中一班');
INSERT INTO `students` VALUES (7, '灰太狼', '男', 30, '高中三班');
INSERT INTO `students` VALUES (8, '红太狼', '女', 30, '高中二班');
 
SET FOREIGN_KEY_CHECKS = 1;

4.外部配置文件jdbc.properties

cx.url=jdbc:mysql://localhost:3306/studb
cx.driver=com.mysql.cj.jdbc.Driver
cx.username=root
cx.password=123456

5.编写配置类

@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:jdbc.properties")
//@EnableAspectJAutoProxy //开启aspectj注解的支持
@EnableTransactionManagement //开启事务注解的支持
public class JavaConfig {
    /*从配置文件中读取数据库连接的相关信息。*/
    @Value("${cx.driver}")
    private String driver;
    @Value("${cx.url}")
    private String url;
    @Value("${cx.username}")
    private String username;
    @Value("${cx.password}")
    private String password;

    //druid连接池,使用 Druid 连接池来管理数据库连接。
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    //创建一个 JdbcTemplate bean,将上面创建的数据源对象注入其中,用于执行数据库查询和更新操作。
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建一个用于管理事务的 TransactionManager bean,将数据源对象注入其中,以便在事务中控制数据库的操作。
    @Bean
    public TransactionManager transactionManager(DataSource dataSource){
        //内部要进行事务的操作,基于的连接池
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        //需要连接池对象
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

6.简单准备一个dao/service层

dao

@Repository
public class StudentDao {
    //声明一个 JdbcTemplate 对象作为成员变量来执行数据库操作。
    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void updateNameById(String name, Integer id){
        String sql = "update students set name = ? where id = ? ;";
        int rows = jdbcTemplate.update(sql, name, id);
    }

    public void updateAgeById(Integer age,Integer id){
        String sql = "update students set age = ? where id = ? ;";
        jdbcTemplate.update(sql,age,id);
    }
}

service(重要内容)

添加事务:

 @Transactional
      位置: 方法 | 类上
      方法: 当前方法有事务
      类上: 类下的所有方法都有事务

 1.只读模式

         只读模式可以提升查询事务的效率! 推荐事务中只有查询代码,使用只读模式!
         默认: boolean readOnly() default false;
         解释: 一般情况下,都是通过类添加注解添加事务!
         类下的所有方法都有事务!
         查询方法可以通过再次添加注解,设置为只读模式,提高效率!

 2.超时时间

         默认: 永远不超时  -1
         设置 timeout = 时间 秒数  超过时间,就会回滚事务和释放异常!         TransactionTimedOutException
        如果类上设置事务属性,方法也设置了事务注解! 方法会不会生效??
        不会生效: 方法上的注解覆盖了类上的注解!

 3.指定异常回滚和指定异常不回滚:

        默认情况下,指定发生运行时异常事务才会回滚!
        我们可以指定Exception异常来控制所有异常都回滚!
        rollbackFor = Exception.class
        noRollbackFor = 回滚异常范围内,控制某个异常不回滚!

 4.隔离级别设置

        推荐设置第二个隔离级别!
        isolation = Isolation.READ_COMMITTED

@Transactional(timeout = 3)//超时时间
@Service
public class StudentService {

    private StudentDao studentDao;

    @Autowired
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    @Transactional(readOnly = false ,rollbackFor = Exception.class , noRollbackFor = FileNotFoundException.class
            ,isolation = Isolation.READ_COMMITTED)
    public void changeInfo() throws FileNotFoundException {
        studentDao.updateAgeById(99, 1);
        new FileInputStream("xxxx");
        studentDao.updateNameById("test3", 1);
    }

    @Transactional(readOnly = true)
    public void changeInfo2() {
        //查询 没有必要添加事务!
        //获取学生信息 查询数据库 不修改
    }

    /**
     * 声明两个独立修改数据库的事务业务方法
     * propagation = Propagation.REQUIRED 父方法有事务,我们就加入到父方法的事务!
     *              最终是同一个事务! 推荐使用默认值!!
     *
     * propagation = Propagation.REQUIRES_NEW
     *               不管父方法是否有事务,我都是独立的事务!
     *               两个事务或者三个事务!
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void changeAge(){
        studentDao.updateAgeById(8,1);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void changeName(){
        studentDao.updateNameById("二狗子",1);
        int i = 1/0; //报错
    }
}

封装类TopService

@Service
public class TopService {
    @Autowired
    private StudentService studentService;
    @Transactional
    public void  topService(){
        studentService.changeAge();
        studentService.changeName();
    }
}

为什么要这个封装类呢?移步以下博客

主要涉及了事务的控制与管理 icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/136966627?spm=1001.2014.3001.5501

7.测试

@SpringJUnitConfig(JavaConfig.class)
public class TxTest {
    @Autowired
    private TopService topService;
    @Autowired
    private StudentService studentService;
    @Test
    public void  testTx() throws FileNotFoundException {
        topService.topService();
    }
}

结果:数据库中age被修改,因为使用的Propagation.REQUIRES_NEW,表示每个方法都会创建一个新的事务,独立于外部事务,即使其他方法报错,正常方法会被执行。

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

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

相关文章

003、Dynamo Python创建楼板

今天我们来创建一块楼板&#xff0c;仍然是找Dynamo里有的节点&#xff0c;可以对照参考练习。 首先&#xff0c;我们打开API手册&#xff0c;在索引里搜索Floor&#xff0c;发现在Floor的方法里&#xff0c;没有找到创建楼板的方法&#xff0c;于是在搜索栏搜索&#xff0c…

python(django(自动化))之流程接口展示功能前端开发

1、创建模板代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav class "navbar n…

电脑如何关闭自启动应用?cmd一招解决问题

很多小伙伴说电脑刚开机就卡的和定格动画似的&#xff0c;cmd一招解决问题&#xff1a; CtrlR打开cmd,输入&#xff1a;msconfig 进入到这个界面&#xff1a; 点击启动&#xff1a; 打开任务管理器&#xff0c;禁用不要的自启动应用就ok了

LangChain核心模块 Retrieval——文本嵌入模型、Vector stores

Text embedding models 文本嵌入模型 检索的另一个关键部分是为文档创建嵌入。 Embeddings 类是设计用于与文本嵌入模型交互的类。 Embeddings创建一段文本的矢量表示&#xff0c;这样我们就可以在向量空间中思考文本&#xff0c;并执行语义搜索之类的操作&#xff0c;在向…

详解库和程序运行过程

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

Websocket + Vue使用

这里有一篇文档可以参考一下> 闪现 POM文件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.0</version> </dependency> WebSocketConf…

IIS7/iis8/iis10安装II6兼容模块 以windows2022为例

因安全狗的提示 安全狗防护引|擎安装失败 可能原因是: IIS7及以上版本末安装1IS6兼容模块! .所以操作解决 如下. 在开始菜单中,找到服务器管理器.找到下图的IIS,右键添加角色和功能,找到web服务器的管理工具选项,iis6管理兼容性 打钩并安装. 如下图

力扣---最长回文子串---二维动态规划

二维动态规划思路&#xff1a; 首先&#xff0c;刚做完这道题&#xff1a;力扣---最长有效括号---动态规划&#xff0c;栈-CSDN博客&#xff0c;所以会有一种冲动&#xff0c;设立g[i]&#xff0c;表示以第i位为结尾的最长回文子串长度&#xff0c;然后再遍历一遍取最大长度即可…

Web前端-JS

JavaScript&#xff0c;简称js&#xff1a;负责网页的行为&#xff08;交互效果&#xff09;。是一门跨平台&#xff0c;面向对象的脚本语言&#xff08;编写出来的语言不需要编译&#xff0c;通过浏览器的解释就可以运行&#xff09; JS引入方式 1.内嵌样式 这样打开页面就会…

【CVPR2024】CricaVPR

【CVPR2024】CricaVPR: Cross-image Correlation-aware Representation Learning for Visual Place Recognition 这个论文提出了一种具有跨图像相关性的鲁棒全局表示方法用于视觉位置识别&#xff08;VPR&#xff0c;Visual Place Recognition &#xff09;任务&#xff0c;命…

Linux系统——iptables超细致解释

目录 内核如何处理数据包流程图 一、表 二、链 三、表、链、规则的关系 四、数据报文进/出节点经过哪些规则 五、NAT——网络地址转换 1.SNAT 2.DNAT 内核如何处理数据包流程图 规则是管理员对数据包制定的一种触发机制&#xff0c;即当数据包达到某种条件&#xff0c;…

【Linux杂货铺】进程控制

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 进程创建 &#x1f4c2; fork函数 &#x1f4c2; 写实拷贝 &#x1f4c2; 创建进程的目的 &#x1f4c2; 创建失败原因 &#x1f4c1; 进程终止 &#x1f4c2; 概念 &#x1f4c2; 场景 &#x1f4c2; 退出方法 …

欧几里得算法-----无聊的军官pro max版本

上篇文章末尾我们说学了欧几里得算法一定给大家更新。 今天它来了&#xff01; 欧几里得算法 欧几里得算法是一种求最小公倍数和最大公因数的算法。 我们看图&#xff1a; 我们把两个数看成长方形&#xff0c;在长方形内不断划分出小正方形&#xff0c;PS&#xff1a;第一个…

一图理解递归-算法通关村

一图理解递归-算法通关村 递归是我们算法进阶的基础&#xff0c;是必须要掌握的内容&#xff0c;只有掌握了递归才算真的会算法。与递归有关的问题有&#xff1a; 与树和二叉树相关的大部问题二分查找相关的问题快速排序、归并排序相关的问题所有回溯的问题所有动态规划的问题 …

scrapy爬虫框架

scrapy爬虫框架 一、scrapy的概念作用和工作流程1、scrapy的概念2、scrapy框架的作用3、scrapy的工作流程&#xff08;重点&#xff09;3.1 回顾之前的爬虫流程3.2 改写上述流程3.3 scrapy的流程3.4 scrapy的三个内置对象3.5 scrapy中每个模块的具体作用 二、scrapy的入门使用1…

【机器学习】无监督学习算法之:主成分分析

主成分分析 1、引言2、主成分分析2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 快&#xff0c;快。 小鱼&#xff1a;… 啥情况&#xff0c; 你可别乱喊。 小屌丝&#xff1a;额… 我的意思&#xff0c;是你该继…

【附订阅OnlyFans攻略】2024年AI:一个交织着创新与挑战的故事

2024年AI&#xff1a;一个交织着创新与挑战的故事 在2024年的一个清晨&#xff0c;阳光透过智能窗户的调节&#xff0c;柔和地洒在书房里。李华&#xff0c;一位年轻的科技创业者&#xff0c;坐在书桌前&#xff0c;凝视着电脑屏幕上不断跳动的数据和图像。他正在进行一项重要…

Flutter 项目架构技术指南

Flutter 项目架构技术指南 视频 https://www.bilibili.com/video/BV1rx4y127kN/ 前言 原文 https://ducafecat.com/blog/flutter-clean-architecture-guide 探讨Flutter项目代码组织架构的关键方面和建议。了解设计原则SOLID、Clean Architecture&#xff0c;以及架构模式MVC…

qt 实现 轮播图效果,且还有 手动 上一页和下一页 已解决

QT中有 轮播图的需求&#xff0c;按照正常html版本 。只需要配置数组就能搞定&#xff0c;但是c qt版本 应该用什么了。 第一想到的是采用定时器。 // 定时器初始化{m_pTime new QTimer(this);m_pTime->start(4 * 1000);//启动定时器并设置播放时间间隔m_pAutoFlag true;/…

网络层(IP层)

IP协议的本质&#xff1a;有将数据跨网络传输的能力 而用户需要的是将数据从主机A到主机B可靠地跨网络传输 IP的组成&#xff1a;目标网络目标主机 IP由目标网络和目标主机两部分组成&#xff0c;IP报文要进行传输&#xff0c;要先到达目标网络&#xff0c;然后经过路由器转到…