[Spring] Spring事务与事务的传播

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 回忆数据库中的事务
  • 2. Spring中事务的实现
    • 2.1 Spring编程式事务
    • 2.2 Spring声明式事务@Transactional
    • 2.3 @Transactional的作用
  • 3. @Transactional详解
    • 3.1 rollbackFor
    • 3.2 事务隔离级别
      • 3.2.1 回顾MySQL中的事务隔离级别
      • 3.3.2 Spring事务隔离级别
    • 3.3 Spring事务传播机制
      • 3.3.1 概念
      • 3.3.2 事务的传播机制分类
      • 3.3.3 Spring事务传播机制代码演示

1. 回忆数据库中的事务

https://lilesily12385.blog.csdn.net/article/details/137935719

2. Spring中事务的实现

Spring中的事务操作分为两类:

  1. 编程式事务(手动写代码操作事务)
  2. 声明式事务(使用注解完成)

现有一需求: 用户注册,注册时候在日志表中插入一条操作记录
数据准备:

DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;
-- ⽤⼾表 
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR (128) NOT NULL,`password` VARCHAR (128) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '⽤⼾表';
-- 操作⽇志表 
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (`id` INT PRIMARY KEY auto_increment,`user_name` VARCHAR ( 128 ) NOT NULL,`op` VARCHAR ( 256 ) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now() 
) DEFAULT charset 'utf8mb4';

代码准备:
1. 创建项目,配置文件引入日志打印,驼峰转换,数据库配置等.

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/trans_test?
characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
mybatis:configuration: # 配置打印 MyBatis⽇志 log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #配置驼峰⾃动转换 

创建实体类:

import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {private Integer id;private String userName;private String password;private Date createTime;private Date updateTime;
}
mport lombok.Data;
import java.util.Date;
@Data
public class LogInfo {private Integer id;private String userName;private String op;private Date createTime;private Date updateTime;
}

Mapper:

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserInfoMapper {@Insert("insert into user_info(`user_name`,`password`)values(#{name},#{password})")Integer insert(String name,String password);
}
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LogInfoMapper {@Insert("insert into log_info(`user_name`,`op`)values(#{name},#{op})")Integer insertLog(String name,String op);
}

Service:

@Slf4j
@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;public void registryUser(String name,String password){//插⼊⽤⼾信息 userInfoMapper.insert(name,password);}
}
 @Slf4j@Servicepublic class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;public void insertLog(String name,String op){//记录⽤⼾操作 logInfoMapper.insertLog(name,"⽤⼾注册");}}

2.1 Spring编程式事务

Spring手动操作事务主要分为三步,与Sql事务的操作类似:
- 开启事务
- 提交事务
- 或者回滚事务

@RestController
@RequestMapping("/user")
public class TransactionController {@Autowiredprivate UserService userService;@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/registry")public String login(String userName,String password){//开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);//用户注册userService.registryUser(userName,password);//提交事务dataSourceTransactionManager.commit(transaction);//回滚事务
//        dataSourceTransactionManager.rollback(transaction);return "注册成功";}
}

SpringBoot内置了两个对象:

  1. DataSourceTransactionManager,数据源事务管理器,一般用于事务的开启回滚和提交.
  2. TransactionDefinition是事务的属性,一般用于传给事务管理器的getTransaction方法,用于事务的获取与开启.
  • 观察事务提交
dataSourceTransactionManager.commit(transaction);

在这里插入图片描述
在这里插入图片描述
我们观察到数据库,数据被插入成功.

  • 观察事务回滚
dataSourceTransactionManager.rollback(transaction);

在这里插入图片描述
在这里插入图片描述
我们看到虽然返回的结果是注册成功,但是数据库中并没有多出任何数据.
下面我们来学习一种简单而快捷的方法,使用注解声明.

2.2 Spring声明式事务@Transactional

一共有两部操作:

  1. 添加依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId>
</dependency>
  1. 在事务的方法上添加@Transactional注解就可以实现了.无需手动开启和提交事务,在事务全部执行完成之后会自动提交,在中途发生异常的手会自动回滚.
@RestController
@RequestMapping("/user2")
public class TransactionController2 {@Autowiredprivate UserService userService;@RequestMapping("/registry2")@Transactionalpublic String registry2(String userName,String password){userService.registryUser(userName,password);return "注册成功";}
}

运行程序后,数据插入成功.
修改程序,使之出现异常:

@RestController
@RequestMapping("/user2")
public class TransactionController2 {@Autowiredprivate UserService userService;@RequestMapping("/registry2")@Transactionalpublic String registry2(String userName,String password){userService.registryUser(userName,password);int i = 10/0;return "注册成功";}
}

运行之后,虽然返回了注册成功,但是数据库并没有更新结果.

我们一般写事务的时候会在业务逻辑层来控制事务,因为在业务逻层中,一个业务功能可能会包含多个数据库访问操作,这样就可以把多个访问数据库的操作 合并在同一个事务中.

2.3 @Transactional的作用

@Transactional可以用来修饰方法或者是类.
修饰方法的时候,只对public修饰的方法生效,修饰其他方法也不会报错,但是也不会生效.
修饰类的时候,对类中的所有public方法生效.
在程序出现异常的时候,如果异常没有被捕获,这时候事务就会被回滚,但是如果异常被捕获,就会被认为是正常执行,依然会提交事务.
修改上述代码:

@RestController
@RequestMapping("/user2")
public class TransactionController2 {@Autowiredprivate UserService userService;@RequestMapping("/registry2")@Transactionalpublic String registry2(String userName,String password){userService.registryUser(userName,password);try {int i = 10/0;}catch (ArithmeticException e) {e.printStackTrace();}return "注册成功";}
}

运行程序之后,虽然出错了,由于异常得到了捕获,事务便得到了提交.
以下两种情况,事务依然会回滚:

  1. 重新抛出异常
try {int i = 10/0;
}catch (ArithmeticException e) {throw e;
}
  1. 手动回滚事务
    使用TransactionAspectSupport.currentTransactionStatus()得到当前事务,并使用setRollbackOnly回滚.
try {int i = 10/0;
}catch (ArithmeticException e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

3. @Transactional详解

我们主要学习@Transactional注解的三个属性:
1. rollbackFor:异常回滚属性,指定能够触发事务回滚的异常类型.可以指定多个异常类型.
2. Isolation:事务的隔离级别,默认是Isolation.DEFAULT.
3. propagation:事务的传播机制.默认值为propagation.REQUIRED

3.1 rollbackFor

异常回滚的时候,@Transactional默认在遇到Error或者运行时异常时才会回滚.
在这里插入图片描述
接下来我们来使用代码验证:

@Transactional
@RequestMapping("/registry3")
public String registry3(String userName,String password) throws IOException {userService.registryUser(userName,password);if (true){throw new IOException();}return "注册成功";
}

向服务器提交数据:
在这里插入图片描述
在这里插入图片描述
我们看到,虽然抛出了异常,但是数据库的数据仍然被修改了.
如果我们要想指定回滚异常的类型,我们需要通过@Transactional的rollbackFor属性来完成,给属性传入异常的类对象来实现对回滚异常的指定,

@RequestMapping("/registry3")
@Transactional(rollbackFor = Exception.class)
public String registry3(String userName,String password) throws IOException {userService.registryUser(userName,password);if (true){throw new IOException();}return "注册成功";
}

运行程序:
在这里插入图片描述在这里插入图片描述
我们看到,事务并没有进行提交,被回滚了,数据库的数据并没有更行.

3.2 事务隔离级别

3.2.1 回顾MySQL中的事务隔离级别

https://lilesily12385.blog.csdn.net/article/details/137935719

3.3.2 Spring事务隔离级别

Spring中事务的隔离级别有5种:

  1. Isolation.DEFAULT: 以连接数据库的隔离级别为准.
  2. Isolation.READ_UNCOMMITTED:读未提交
  3. Isolating.READ_COMMITTED:读提交.
  4. Isolation.REPEATABLE_READ:可重复读.
  5. Isolation.SERIALIZABLE:串行化.
public enum Isolation {DEFAULT(-1),READ_UNCOMMITTED(1),READ_COMMITTED(2),REPEATABLE_READ(4),SERIALIZABLE(8);private final int value;private Isolation(int value) {this.value = value;}public int value() {return this.value;}
}

Spring中的隔离级别可以通过@Transactional中的Isolation属性进行设置.

@RequestMapping("/registry3")
@Transactional(isolation = Isolation.DEFAULT)
public String registry3(String userName,String password) throws IOException {userService.registryUser(userName,password);return "注册成功";
}

3.3 Spring事务传播机制

3.3.1 概念

事务的传播机制就是:多个事务方法存在调用关系的时候,事务是如何在这些方法之间进行传播的.事务的传播机制就解决的是一个事务在多个节点上(方法)中的传递.
在这里插入图片描述

比如有两个方法A和B,他们都被@Transactional修饰,方法A调用了方法B.A方法运行的时候,会开启一个新的事物,当A调用B的时候,B方法本身也有事务,此时B方法运行的时候,是假如A事务,还是创建一个新的事务呢?下面我们就来介绍一下事务的传播机制.

3.3.2 事务的传播机制分类

@Transactional注解支持事务的传播机制的设置,我们可以通过propagation属性来设置传播行为.

  1. Propagation.REQUIRED:加入事务,默认的事务传播级别.如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务.(加入事务,就是共用一个事务,一个事务发生异常,全部回滚.)
  2. Propagation.SUPPORTS:如果当前存在事务,则加入该事务.如果当前没有事务,则以非事务的方式继续运行.
  3. Propagation.MANDATORY:强制性,如果当前存在事务,则加入该事务,如果当前没有事务,则抛出异常.
  4. Propagation.REQUIERS_NEW:新建事务,创建一个新事务如果当前存在事务,则把当前事务挂起.(发生异常,不影响其他事务)也就是不管外部方法是否开启事务,Propagation.REQUIERS_NEW修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干涉.
  5. Propagation.NOT_SUPPORTED: 以非事务的方式运行,如果当前存在事务则把当前事务挂起.
  6. Propagation.NEVER: 不支持当前事务,以非事务的方式运行,如果存在事务,则抛出异常.
  7. Propagation.NESTED: 嵌套事务,如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则该取值等价于Propagation.REQUIRED.
    1,4对应,2,5对应,3,6对应.
public enum Propagation {REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);private final int value;private Propagation(int value) {this.value = value;}public int value() {return this.value;}
}

举例说明:一对新人结婚,需要房子

  1. Propagation.REQUIRES: 如果你有房子,就住你的房子(加入事务),如果你没有房子,我们就一起买房子(创建一个新事务).
  2. Propagation.SUPPORTS: 如果你有房子,我们就住你的房子(加入事务),如果没有房子,我们就租房子(以非事务的方式运行).
  3. Propagation.MANDATORY: 要求必须有房子(加入事务),如果没有房子,就不结婚(抛出异常)
  4. Propagation.REQUIERS_NEW: 必须买新房,不管你有没有房子,必须两个人一起买房(创建一个新事务),即使有房也不住(当前事务挂起).
  5. Propagation.NOT_SUPPORTED: 不管你有没有房子,我都不住(挂起当前事务),必须租房(以非事务的方式运行).
  6. Propagation.NEVER:不能有房子(当前存在事务),有房子就不结婚(抛出异常).
  7. Propagation.NESTED :如果你没房,就⼀起买房.如果你有房,我们就以房子为根据地,做点下生意.(如果如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运行.如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED )

3.3.3 Spring事务传播机制代码演示

重点关注两个: REQUIRED,REQUIERS_NEW.

  • REQUIRED(加入事务)
    用户注册,插入一条数据,并记录操作日志.
@RequestMapping("/r4")
@Transactional
public String registry4(String userName,String password){userService.registryUser(userName,password);logService.insertLog(userName,"用户注册");return "注册成功";
}
@Service
public class UserService {@Autowiredpublic UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public void registryUser(String name,String password) {userInfoMapper.insert(name, password);}
}
@Service
public class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public void insertLog(String name,String op){int i = 10/0;//记录⽤⼾操作logInfoMapper.insertLog(name,"⽤户注册");}
}

我们在执行之后,发现数据库中并没有插入任何数据,这就是因为insertLog方法发生了异常,事务发生回滚,当事务回滚之后,registry4方法也发生了回滚,导致了registryUser也发生了回滚,导致数据库中没有插入数据.

  • REQUIRES_NEW(新建事务)
    将上面的UserService和LogService的事务传播机制改为Propagation.REQUIRES_NEW.
@RequestMapping("/r4")
@Transactional
public String registry4(String userName,String password){userService.registryUser(userName,password);logService.insertLog(userName,"用户注册");return "注册成功";
}
@Service
public class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.REQUIRES_NEW)public void insertLog(String name,String op){int i = 10/0;//记录⽤⼾操作logInfoMapper.insertLog(name,"⽤户注册");}
}
@Service
public class UserService {@Autowiredpublic UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.REQUIRES_NEW)public void registryUser(String name,String password) {userInfoMapper.insert(name, password);}
}

在执行之后,我们会发现,日志表中并没有插入新的数据,但是用户表中插入了新的数据,这是由于UserService,LogServiceregistry4属于不同的事务,LogService出现异常回滚之后不会影响registry4UserService的执行.

  • NEVER(不支持当前事务)
    REQUIRED代码的UserService中的对应方法的事务传播机制修改为Propagation.NEVER.并去掉制造的异常.
@Transactional(propagation = Propagation.NEVER)
public void insertLog(String name,String op){//记录⽤⼾操作logInfoMapper.insertLog(name,"用户注册");
}

运行之后,程序抛出异常,日志表和用户表均没有数据插入.

  • NESTED(嵌套事务)
    将上述REQUIREDUserService中的对应方法的事务传播机制修改为Propagation.NESTED.
@Transactional(propagation = Propagation.NESTED)
public void insertLog(String name,String op){int i = 10/0;//记录用户操作logInfoMapper.insertLog(name,"用户注册");
}
@Transactional(propagation = Propagation.NESTED)`在这里插入代码片`
public void registryUser(String name,String password) {userInfoMapper.insert(name, password);
}

运行程序之后,两张表中都没有插入任何数据,如果我们对出现异常的方法进行手动回滚:

@Transactional(propagation = Propagation.NESTED)
public void insertLog(String name,String op){try {int i = 10/0;}catch (Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}//记录用户操作logInfoMapper.insertLog(name,"用户注册");
}

在这里插入图片描述
我们看到,用户表插入成功了,但是日志表的数据被回滚了.
在这里插入图片描述
在这里插入图片描述

区分REQUIRED和NESTED
REQUIRED:当其中一个事务出现异常的时候,所有事务都会回滚,如果try-catch语句中对事物进行手动回滚,则子事务和父事务全部会被回滚.
NESTED : 当子事务出现异常的时候,子事务对应的父事务也会回滚,但是如果在有异常的子事务中进行try-catch,catch中对事务进行手动回滚,则只有出现异常的事务被回滚,但是另一个没有出现异常的子事务没有被回滚,与REQUIRED最大的区别就是,NESTED可以做到部分回滚,但是REQUIRED只能做到全部回滚.

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零基础学习大模型

揭秘大模型智能背后的神秘力量 前言 在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面。其中&#xff0c;大模型&#xff08;LLM&#xff09;以其强大的语言处理能力和广泛的应用场景&#xff0c;成为了AI领域的一颗璀璨明珠…

Qt 使用阿里矢量图标库

前言 阿里矢量图标库非常好用&#xff0c;里面有各种丰富的图标&#xff0c;完全免费&#xff0c;还支持自定义图标&#xff0c;还可以将图标打包到一个项目中&#xff0c;使用起来非常方便。 第一步&#xff1a; 打开阿里矢量图标库 第二步&#xff1a; 搜索图标&#x…

pcl-滤波模块

点云需要滤波的原因 点云数据密度不规则需要平滑因为遮挡等问题造成离群点需要去除大量数据需要下采样噪音数据需要去除 1.直通滤波 对指定的某一维度实行简单的滤波&#xff0c;就是类似于2D处理中的画ROI&#xff0c;此滤波可以将x&#xff08;y和z&#xff09;在某一范围…

Datawhale X 魔搭 AI夏令营第四期 魔搭-AIGC方向 task03笔记

Datawhale官方的Task3链接&#xff1a;Task03 往期Task1、Task2链接&#xff1a;Task01&#xff0c; Task02 【学习者手册】&#xff1a;链接直达 【QA文档】&#xff1a;链接直达 【赛事官网】&#xff1a;链接直达 ComfyUI ComfyUI是一个基于深度学习的图像生成软件&…

【Linux操作系统】进程概念

目录 一、进程概念1.1 什么是进程 二、task_struct内容分类2.1 标识符2.2 进程状态2.2.1 进程排队2.2.2 关于进程状态的表述——运行、阻塞、挂起2.2.3 Linux中具体的进程状态2.2.4 孤儿进程 2.3 进程优先级 三、Linux的调度与切换3.1 进程切换3.2 进程调度 四、环境变量4.1 ma…

【Redis】Redis 数据类型与结构—(二)

Redis 数据类型与结构 一、值的数据类型二、键值对数据结构三、集合数据操作效率 一、值的数据类型 Redis “快”取决于两方面&#xff0c;一方面&#xff0c;它是内存数据库&#xff0c;另一方面&#xff0c;则是高效的数据结构。 Redis 键值对中值的数据类型&#xff0c;也…

C++练习备忘录

1. 保留两位小数输出格式 #include <iostream> #include <iomanip> using namespace std; int main() {double S 0;S (15 25) * 20 / 2;cout << fixed << setprecision(2) << S;return 0; }2. 设置输出宽度 #include <iostream> #inclu…

自研低代码海报制作平台学习分享计划

vue3组件库开发前面咱卷完了JuanTree组件&#xff0c;接下来一起来卷vue3低代码海报制作平台的基础组件实现。首先是拖拽基础组件的开发&#xff0c;整好把前面学习的知识点再运用进来。 文章目录 效果演示基本拖拽区域拖拽旋转其他效果待实现 录屏说明 看一步步实现的效果&…

【鸿蒙学习】HarmonyOS应用开发者基础 - 构建更加丰富的页面(一)

学完时间&#xff1a;2024年8月14日 一、前言叨叨 学习HarmonyOS的第六课&#xff0c;人数又成功的降了500名左右&#xff0c;到了3575人了。 二、ArkWeb 1、概念介绍 ArkWeb是用于应用程序中显示Web页面内容的Web组件&#xff0c;为开发者提供页面加载、页面交互、页面调…

python实现每天定时发送邮件

文章目录 步骤 1: 安装所需的库步骤 2: 编写发送电子邮件的 Python 脚本步骤 3: 配置电子邮件发送服务步骤 4: 运行脚本进一步扩展 要编写一个用于自动发送每日电子邮件报告的 Python 脚本&#xff0c;并配置它在每天的特定时间发送电子邮件&#xff0c;使用 smtplib 和 emai…

java基础进阶——log日志、类加载器、XML、单元测试、注解、枚举类

前言 这篇内容主要掌握的就是logback使用、理解类加载器、XML文件的编写&#xff0c;XML文档约束schema&#xff0c;用Dom4j解析XML文档&#xff0c;Xpath检索XML文档&#xff0c;完整使用Junit单元测试框架常用部分&#xff0c;注解的定义和使用&#xff0c;枚举类的定义和开发…

二叉树(二)

一、二叉树的顺序结构 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆&#xff08;一种二叉树&#xff09;使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统虚拟…

Self-Supervised Learning(李宏毅老师系列)

自学参考&#xff1a; BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding BERT 论文逐段精读 视频课 课件资料 笔记 一、概述 自监督学习模型与芝麻街~ 参数量 ELMO&#xff1a;94MBERT&#xff1a;340MGPT-2&#xff1a;1542MMegatron&…

ubuntu查看CPU、内存、硬盘

1、查看CPU cat /proc/cpuinfo 我这台机器CPU是2核&#xff0c;所以这里是2核 或者使用如下命令也可以查看 lscpu 查看CPU使用率 top 2、查看内存 查看内存信息&#xff1a; free -h 查看内存使用情况&#xff1a; vmstat 3、硬盘 查看硬盘使用情况&#xff1a; df -…

uniapp 日常业务 随便写写 源码

现成的组件 直接用 <template><view style"margin: 10rpx;"><view class"tea-header"><text class"tea-title">礼尚往来</text><view class"tea-view-all"><text>查看全部</text>&l…

免费录屏软件之QQ

录屏太简单了 1、首先下载QQ 2、在随便打开个对话框&#xff0c;再操作1、2步骤即可 3、嫌打开对话框麻烦&#xff1f; 4、打开QQ后直接按下CtrlAltR即可录屏&#xff0c;连对话框都不用打开了&#xff0c;按完快捷键后效果如下&#xff1a; 5、点击右下角开始录屏即可

Electron:摄像头录制和屏幕录制

摄像头录制 main.js const { app, BrowserWindow} require(electron)let mainWin null const createWindow () > {mainWin new BrowserWindow({width: 800,height: 600,title: 自定义菜单,webPreferences: {// 允许渲染进程使用nodejsnodeIntegration: true,// 允许渲…

idea付费插件激活

以下idea付费插件均可激活 获取链接&#xff1a;https://web.52shizhan.cn

【Qt开发】QtCharts图表 在ui上添加QChartView控件并进行绘图配置

【Qt开发】QtCharts图表 在ui上添加QChartView控件并进行绘图配置 文章目录 控件安装和模块导入在ui上添加QChartView控件QChartView图表配置附录&#xff1a;C语言到C的入门知识点&#xff08;主要适用于C语言精通到Qt的C开发入门&#xff09;C语言与C的不同C中写C语言代码C语…

Datawhale X 魔搭 AI夏令营 Task1 从零入门AI生图原理实践笔记

赛题内容 参赛者需在可图Kolors模型的基础上训练LoRA模型&#xff0c;生成无限风格&#xff0c;如水墨画风格、水彩风格、赛博朋克风格、日漫风格… 基于LoRA模型生成8张图片组成连贯故事&#xff0c;故事内容可自定义&#xff1b;基于8图故事&#xff0c;评估LoRA风格的美感度…