Spring事务管理 -- Spring入门保姆级教程(五)

news2024/11/24 18:46:02

文章目录

  • 前言
  • 六、Spring事务
    • 1.Spring事务简介
    • 2.入门案例--模拟银行间转账业务
    • 3.开启Spring事务的一般步骤
    • 4.Spring事务角色
    • 5.spring事务属性--rollbackfor
    • 6.入门案例进阶--转账业务追加日志
    • 7. Spring事务属性--事务传播行为
  • 总结


前言

为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

六、Spring事务

1.Spring事务简介

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID:

原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。

一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。

隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。

持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:

使用 begin transaction 命令开始事务。

使用 SQL 查询语句执行各种删除、更新或插入操作。

如果所有的操作都成功,则执行提交操作,否则回滚所有操作。

Spring 框架在不同的底层事务管理 APIs 的顶部提供了一个抽象层。Spring 的事务支持旨在通过添加事务能力到 POJOs 来提供给 EJB 事务一个选择方案。Spring 支持编程式和声明式事务管理。EJBs 需要一个应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现,实现接口及实现类如下:

在这里插入图片描述

2.入门案例–模拟银行间转账业务

  1. 案例需求以及实现思路

在这里插入图片描述

  1. 环境准备
  • 创建数据库表tbl_account

建表查询语句示例

create database spring_db;
use spring_db;

drop table if exists tbl_account;

create table tbl_account(
	id int primary key auto_increment,
	name varchar(20),
	money varchar(20)
);

INSERT INTO tbl_account VALUES (1, 'Tom', 1000);
INSERT INTO tbl_account VALUES (2, 'Jerry', 1000);

效果

在这里插入图片描述

  • 在pom.xml文件中导入坐标
 <dependencies>
    //spring框架
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    
    //druid数据源
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

    //mybatisa框架
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>

    //数据库连接
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>

    //spring操作jdbc
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

    //spring整合mybatis
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>

    //spring整合junit单元测试
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    
    //单元测试
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

  </dependencies>
  • 创建spring全局配置文件SpringConfig
 @Configuration
 @ComponentScan("com.itheima")
 @PropertySource("classpath:jdbc.properties")
 @Import({JdbcConfig.class,MybatisConfig.class})
 //开启注解式事务驱动
 @EnableTransactionManagement
 public class SpringConfig {
 }

  • 创建数据库信息文件jdbc.properties,填写数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root
  • 创建数据库连接配置类JdbcConfig
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }

    //配置事务管理器,mybatis使用的是jdbc事务
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  • 创建mybatis创建SqlSessionFactory Bean 和 Mapper 代理开发映射对象配置文件MybatisConfig
public class MybatisConfig {

    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("org.example.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("org.example.dao");
        return msc;
    }
}

  • 根据数据库表创建对应的实体类Account
public class Account{
    //此处省略getter、setter和toString方法
    private Integer id;
    private String name;
    private Double money;
    
}
  • 创建AccontDao接口,用注解的方式定义mapper代理开发业务接口,分别为加钱的操作方法 inmoney 和 减钱的操作 outmoney
public interface AccountDao {

    @Update("update tbl_account set money = money + #{money} where name = #{name}")
    void inMoney(@Param("name") String name, @Param("money") Double money);

    @Update("update tbl_account set money = money - #{money} where name = #{name}")
    void outMoney(@Param("name") String name, @Param("money") Double money);
}
  • 创建业务层接口AccountService,定义转账操作方法transfer
public interface AccountService {
    /**
     * 转账操作
     * @param out 传出方
     * @param in 转入方
     * @param money 金额
     */
    //配置当前接口方法具有事务
    @Transactional
    public void transfer(String out,String in ,Double money) ;
}

  • 创建业务层接口 AccountService 的实现类AccountServiceImpl,调用数据层功能的加钱和减钱方法 inmoney 和 outmoney
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

    public void transfer(String out,String in ,Double money) {
        //减钱
        accountDao.outMoney(out,money);
        //加钱
        accountDao.inMoney(in,money);
    }

}

  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testTransfer() throws IOException {
        //Tom 向 Jerry 转100元
        accountService.transfer("Tom","Jerry",100D);
    }

}
  • 程序运行结果

在这里插入图片描述
在这里插入图片描述

  • 文件结构参考

在这里插入图片描述

  1. 入门案例分析
  • 入门案例完成了简单的模拟转账操作,此时我们在转账接口的实现类AccountServiceImpl减钱和加钱的操作中间添加一行模拟业务运行异常的代码,此时我们希望业务异常,终止操作,即数据库的账户余额不变。

  • 添加了模拟异常的代码及运行结果
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 通过观察数据库中的表格数据我们发现异常前面的减钱操作运行了,而异常后面的加钱操作没有运行,导致整体业务功能失败。我们可以通过开启Spring事务来解决这个问题。
  1. 小结
  • Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
  • 注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
  • 事务管理器需要根据实现技术进行选择,mybatis使用的是jdbc事务

3.开启Spring事务的一般步骤

  1. @Transactional 注解配置对应的接口方法具有事务
    @Transactional
    public void transfer(String out,String in ,Double money) ;
}

  1. 配置事务管理器,mybatis使用的是jdbc事务
public class JdbcConfig {
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

  1. @EnableTransactionManagement 注解开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {

}

此时在存在模拟异常的情况下再次运行模拟测试类,数据库中的数据不变,业务功能运行正常,Spring事务开启成功。

4.Spring事务角色

  1. Spring事务角色分为事务管理员和事务协调员
  • 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法

  • 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

  1. 结合入门案例分析

在这里插入图片描述

  • 在入门案例中,没加@Transactional注解开启事务的情况下,减钱的outmoney方法、加钱的方法inmoney以及transfer接口都会各自开启一个事务,各自独立。当运行加钱事务出现异常的时候,减钱操作并不会加入加钱操作的事务回滚中,导致整个业务运行失败。

  • 当只用@Transactional注解开启事务后,事务减钱事务TI与加钱事务T2都加入事务T,成为一个事务,这样当事务中的加钱事务部分出现问题时,整个事务回滚,程序终止运行,整体业务正常运行成功。

5.spring事务属性–rollbackfor

  1. 属性简介
属性作用示例
readonly设置是否为只读事务readOnly=true 只读事务
timeout设置事务超时时间timeout=-1(永不超时)
rollbackfor设置事务回滚异常(class){NullPointException.class rollbackFor=
rollbackForClassName设置事务回滚异常(string)同上格式为字符串
noRollbackFor设置事务不回滚异常(class)noRollbackFor= (NullPointException.class}
noRollbackForClassName设置事务不回滚异常(string)同上格式为字符串
propagation设置事务传播行为
  1. 添加事务属性格式举例
public interface AccountService {
    /**
     * 转账操作
     * @param out 传出方
     * @param in 转入方
     * @param money 金额
     */
    //配置当前接口方法具有事务
    @Transactional(readOnly = true,timeout = -1)
    public void transfer(String out,String in ,Double money) ;
}
  1. rollbackfor 属性介绍
  • 在业务层实现类中抛出一个IOException异常
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    public void transfer(String out,String in ,Double money) throws IOException {
        accountDao.outMoney(out,money);
        //模拟抛出IOException异常
        if(true){throw new IOException();}
        accountDao.inMoney(in,money);
    }

}

  • 运行模拟测试类

在这里插入图片描述
在这里插入图片描述

  • 观察数据库表我们发现,开启事务后在遇到抛IOException类型的异常时,事务不会主动回滚,导致整体业务失败,这时候需要主动去配置。
public interface AccountService {
    /**
     * 转账操作
     * @param out 传出方
     * @param in 转入方
     * @param money 金额
     */
    //配置当前接口方法具有事务
    @Transactional(rollbackFor = {IOException.class})
    public void transfer(String out,String in ,Double money) throws IOException;
}

此时再次运行模拟测试类,当检测到IOExctpition类型的异常时,事务T回滚,数据库表中的数据不变。

  • 开启Spring事务只回滚两种事务:ERROR系列(如内存溢出) 和 运行时异常(如NO Point Exception)。其余的均需要通过rollbackfor属性手动配置。

6.入门案例进阶–转账业务追加日志

  1. 案例需求及实现思路

在这里插入图片描述

  1. 编码环境准备
  • 创建数据库表tbl_log

sql建表语句

use spring_db;

drop table if exists tbl_log;

create table tbl_log(
	id int primary key auto_increment,
	info varchar(100),
	createDate varchar(20)
);

INSERT INTO tbl_log VALUES (1, '转账操作由Tom到Jerry,金额:100.0', '20:55:49');

表格示例

在这里插入图片描述

  • LogDao数据层接口
public interface LogDao {
    @Insert("insert into tbl_log (info,createDate) values(#{info},now())")
    void log(String info);
}

  • LogService 业务层接口
public interface LogService {
    @Transactional
    void log(String out, String in, Double money);
}

  • LogService 业务层接口实现类
@Service
public class LogServiceImpl implements LogService {

    @Autowired
    private LogDao logDao;

    public void log(String out,String in,Double money ) {
        logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
    }
}
  • 将IOException相关的代码注释掉,保留最基础的Spring事务代码

  • 文件结构示例

在这里插入图片描述

  1. 用try…finally结构编写业务层实现类AccountServiceImpl 并运行测试类
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private LogService logService;

    public void transfer(String out,String in ,Double money) {
        try{
            accountDao.outMoney(out,money);
            int i = 1/0;
            accountDao.inMoney(in,money);
        }finally {
            logService.log(out,in,money);
        }
    }

}

  • 将数据库中的金额分别手动修改重置到1000,并执行测试类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

7. Spring事务属性–事务传播行为

  1. 探讨添加了异常后,日志能否正常加载

在这里插入图片描述

  • 运行结果分析

此时再次运行测试类,我们可以发现数据库表中金额表数值由于开启了事务,当出现异常时,事务回滚,金额数值不变。同时日志表的数据也没有发生变化,不符合我们的预期。

  • 存在的问题:

日志的记录与转账操作隶属同一个事务,同成功同失败

在这里插入图片描述

  • 实现效果预期改进:

无论转账操作是否成功,日志必须保留,这时就需要通过事务传播行为来解决这个问题

在这里插入图片描述

  1. spring事务的7种传播行为
required(默认传播行为),如果当前有事务,其他就用当前事务,不会新增事务。例如:方法A调用方法B,它们用同一个事务。(如果B没有事务,它们会用同一个事务。)(只要有一个回滚,整体就会回滚)
requires_new如果当前有事务,其他不会加入当前事务,会新增事务。即他们的事务没有关系,不是同一个事务。如果其他没有事务,那么以当前事务运行。例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务)
supports当前没有事务,就以非事务运行。当前有事务呢?就以当前事务运行。例如:方法A调用方法B,如果A没有事务,那么B就以非事务运行。如果A有事务就以A事务为准。如果A没有事务,那么B就会以非事务执行。
mandatory其他没有事务就会抛异常。当前没有事务抛出异常,当前有事务则支持当前事务。支持当前事务,如果当前没有事务就会抛出异常。例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。
not_supported以非事务执行。例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。
never以非事务执行,如果存在事务,抛出异常。总是以非事务执行,如果存在事务,那么就抛出异常。
nested如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与Required一样。例如:方法A中调用了方法B,B中try catch手动回滚,A不会回滚。
  1. 设置日志接口方法的事务传播行为属性
public interface LogService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    void log(String out, String in, Double money);
}
  1. 运行测试类观察效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
基于以上结果,Spring事务传播行为设置成功,业务功能运行正常。

总结

欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

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

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

相关文章

ZIP/RAR压缩包加密原理和解密方法

ZIP/RAR压缩包加密原理和解密方法 1、压缩包的概念 一般我们看到的压缩格式有.rar&#xff0c;.zip&#xff0c;等等有许多格式但主要压缩的作用就是让某一个文件占用空间小点。比如原来是50MB,可以压缩到30多MB。 压缩包的算法&#xff1a; 有许多不同的压缩格式例如&#…

【MySQL】-【数据库的设计规范】

文章目录 为什么需要数据库设计范式范式简介范式都包括哪些键和相关属性的概念 为什么需要数据库设计 范式 范式简介 在关系型数据库中&#xff0c;关于数据表设计的基本原则、规则就称为范式。可以理解为&#xff0c;一张数据表的设计结构需要满足的某种设计标准的 级别 。要…

第二届欧亚计算机科学与信息技术前沿国际会议

会议简介 Brief Introduction 2023年第二届欧亚计算机与信息技术前沿国际会议(FCSIT 2023) 会议时间&#xff1a;2023年9月15 -17日 召开地点&#xff1a;英国牛津 大会官网&#xff1a;www.ecfcsit.org 2023年计算机与信息技术前沿国际会议(FCSIT 2023)将围绕“计算机与信息技…

单词长度统计-列表

输入一段英文计算每个单词长度&#xff0c;统计不含非英文字符&#xff0c;列表输出。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… 地址…

Java高并发核心编程(JUC)—线程详细笔记

进程 线程 线程方法 线程原理 线程状态 查看线程 进程 概述 进程&#xff1a;程序是静止的&#xff0c;进程实体的运行过程就是进程&#xff0c;是系统进行资源分配的基本单位. 一般来说&#xff0c;一个进程由程序段&#xff08;包含代码、指令集合)、数据段&#xff08;进程…

Gitlab的使用教程

Gitlab的基本介绍&#xff1a; Gitlab是利用Ruby on Rails 一个开源的版本管理系统&#xff0c;实现一个自托管的git项目仓库&#xff0c;可通过web界面进行访问公开或私有的项目。 与GitHub类似&#xff0c;Gitlab能够浏览源代码、管理缺陷和注释、可以管理团队对仓库的访问…

YSL赢麻了?SMI社媒心智品牌榜Top20公布:YSL破局夺魁,国货品牌现后起之秀

全文速览 1.数说故事联合用户说从美妆、彩妆、护肤三板块全新发布《SMI社媒心智品牌榜》。 2.圣罗兰、兰蔻、欧莱雅等法国高端美妆大牌垄断美妆《SMI社媒心智品牌榜》前三甲。 3.彩妆Top20榜单中&#xff0c;底妆产品稳居前列&#xff0c;色彩美妆占据一席之地。 4.护肤TOP…

Java面试知识点(全)-分布式微服务-zookeeper面试知识点

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 ZooKeeper是什么&#xff1f; ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&…

现在转行想学云计算?这些知识你需要提前掌握!

现在转行想学云计算&#xff1f;这些知识你需要提前掌握&#xff01; 近年来&#xff0c;云计算技术和应用正铺天盖地向我们袭来&#xff0c;工作、生活、娱乐、教育、金融、科技、工业、农业等各个领域都有他的身影。什么是“云”&#xff1f;“云”是一个庞大的可容纳海量资源…

医疗科普系统和微信小程序开箱即用

一.下载地址 http://www.gxcode.top/code 二.项目说明 运行环境&#xff1a;jdk8tomcat8mysql5.7IntelliJ IDEAmaven微信开发工具 这是一个ssmvue微信小程序的医疗科普小程序&#xff0c;分为pc端和微信小程序端&#xff0c; pc端包括&#xff1a;管理员角色和学生角色。 管…

【LeetCode】168. Excel表列名称

168. Excel表列名称&#xff08;简单&#xff09; 思路 显然&#xff0c;这是一道从 1 开始的的 26 进制转换题。 对于一般性的进制转换题目&#xff0c;只需要不断地对 columnNumber 进行 % 运算取得最后一位&#xff0c;然后对 columnNumber 进行 / 算&#xff0c;将已经取得…

【项目源码】基层医院信息化管理系统HIS源码

医院信息系统&#xff08;HIS&#xff09;经历了从手工到单机再到局域网的两个阶段&#xff0c;随着云计算、大数据新技术迅猛发展&#xff0c;基于云计算的医院信息系统将逐步取代传统局域网HIS,以适应人们对医疗卫生服务越来越高的要求。 利用云计算、大数据等现代信息技术研…

Windows下安装docker

Windows下安装docker 1.安装WSL2 我的Windows版本如下&#xff1a; 版本 Windows 11 专业版 版本 22H2 1.1 检查能否安装 必要条件&#xff1a; Windows 10 对于 x64 系统&#xff1a;版本 1903 或更高版本&#xff0c;内部版本为 18362 或更高版本。对于 ARM64 系统&…

5个值得一试的开源大语言模型

5个值得一试的开源大语言模型 人工智能已经成为我们生活中不可或缺的一部分&#xff0c;而LLM&#xff08;大型语言模型&#xff09;处于这一变化的最前沿。 在对话式人工智能方面&#xff0c;大语言模型的性能最为关键。 虽然像 OpenAI 的 GPT-4 这样的商业大语言模型已经引起…

jdk13至15——文本块特性

文本块在jdk13中第一次预览&#xff0c;jdk14第二次预览&#xff0c;jdk15正式版&#xff1b; 终于不用在多行字符串中加一堆\n和一堆\"和一堆了&#xff1b; 之前需要这么麻烦&#xff1a; Testvoid test() {String s "testabcd\n" "aaa\n" "…

【机器学习】贝叶斯分类与概率图模型

文章目录 第五章 贝叶斯分类与概率图模型5.1、贝叶斯决策与贝叶斯分类5.1.1、贝叶斯基本原理5.1.2、朴素贝叶斯分类器&#xff08;naive bayes&#xff09;5.1.3、半朴素贝叶斯 5.2、有向图与无向图一般概念5.2.1、有向图5.2.2、无向图5.2.3、条件独立性5.2.4、图模型推理的概念…

海睿思分享 | 浅谈企业数据资产管理

1、什么是数据资产 与实物资产、无形资产一样&#xff0c;数据资产首先表现为是一种资源。也就是说&#xff0c;并非所有的数据资源都可以升级为数据资产。作为“资产”的数据资源&#xff0c;大体表现为以下两种形式&#xff1a;一是可以通过合理应用创造出新的价值。二是通过…

【k8s】Jenkins实现Java springboot应用CI、CD实践 【二】

一、运行Jenkins流水线流程思路&#xff1a; 场景1&#xff1a;常规java应用&#xff0c;使用jenkins pipeline 交付到Kubernetes集群中1、准备好java代码、Dockerfile、 deploy. yaml资源清单文件CI阶段: 1、获取代码 2、漏洞扫描 3、检测漏洞扫描结果&#xff0c;如果正常则…

OpenAI ChatGPT3.5-turbo实际解决问题能力评测

OpenAI ChatGPT3.5-turbo实际解决问题能力评测 ​ 程序员在coding的时候会经常遇到需要查阅资料的情况&#xff0c;最好的结果是直接能拿到一份好用的demo版本code&#xff0c;本次我们来评测&#xff1a;bing搜索和chatGPT3.5&#xff0c;解决实际问题&#xff1a;“html 图片…

【Proteus仿真】51单片机矩阵按键+中断+数码管显示+串口输出

【Proteus仿真】51单片机矩阵按键中断数码管显示串口输出 &#x1f4cc;相关篇《【Proteus仿真】51单片机矩阵按键扫描外部中断使用》&#x1f4cd;《【Proteus仿真】51单片机串口输出实验》&#x1f388; 《【Proteus仿真】51单片机定时器计数共阴数码管驱动显示》 &#x1f5…