【源码】SpringBoot事务注册原理
前言
对于数据库的操作,可能存在脏读、不可重复读、幻读等问题,从而引入了事务的概念。
事务
1.1 事务的定义
事务是指在数据库管理系统中,一系列紧密相关的操作序列,这些操作作为一个单一的工作单元执行。事务的特点是要么全部成功,要么全部失败,不会出现部分完成的情况。如果事务中的任何一个操作失败,那么整个事务都会被回滚到开始之前的状态,以确保数据库的一致性和完整性。
1.2 事务的特性
事务具有4个特性:原子性、一致性、隔离性和持久性。通常称为ACID。
1)原子性(Atomicity)
事务是一个不可分割的工作单位,事务中包含的所有操作要么全部成功,要么全部失败。
2)隔离性(Isolation)
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的。
3)持久性(Durability)
一旦事务提交成功,则其所做的修改就会永久保存在数据库中,即使发生系统故障也不会丢失。
4)一致性(Consistency)
事务必须确保数据库从一个一致性状态转变到另一个一致性状态。
更准确的说,事务是通过原子性、隔离性和持久性,实现了事务的一致性。另外,一致性还需要额外的工作来保证,如转账,从A转给B,A的资金减少了,B的资金增加了。转账要么成功、要么失败,但不管成功还是失败,事务的一致性要求两人的资金之和必须一致,要么成功,A减少了、B增加了,要么失败,A和B的资金都不变。为了一致性,需要程序来开启事务,同时修改A和B的资金,从而才能保证一致性。
SpringBoot自动装载
在SpringBoot框架中,会自动引入TransactionAutoConfiguration。且在META-INF的spring-autoconfigure-metadata.properties有如下配置:
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration=
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration=
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration.ConditionalOnBean=org.springframework.transaction.TransactionManager
说明在自动引入TransactionAutoConfiguration时,必须存在TransactionManager的bean,且要先引入内部类EnableTransactionManagementConfiguration。
EnableTransactionManagementConfiguration
内部类EnableTransactionManagementConfiguration的源码如下:
public class TransactionAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnBean(TransactionManager.class)@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)public static class EnableTransactionManagementConfiguration {@Configuration(proxyBeanMethods = false)@EnableTransactionManagement(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")public static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableTransactionManagement(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)public static class CglibAutoProxyConfiguration {}}
}
EnableTransactionManagementConfiguration内中会自动引入JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration,且添加了@EnableTransactionManagement注解。该注解会自动引入TransactionManagementConfigurationSelector。TransactionManagementConfigurationSelector的父类实现了ImportSelector接口,该类的selectImports()方法返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration类名数组,即AutoProxyRegistrar和ProxyTransactionManagementConfiguration会自动注入到Spring IOC容器中。
Spring的配置类解析的时候,会执行ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports),在该方法中,判断importCandidates是否继承于ImportSelector接口,如果是,调用ImportSelector的selectImports()方法,获取需要额外自动加入容器的类。
ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration的源码如下:
package org.springframework.transaction.annotation;/*** Transaction事务管理代理的配置类*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {/*** 返回一个BeanFactoryTransactionAttributeSourceAdvisor【继承AbstractBeanFactoryPointcutAdvisor,重* 写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut】* @return*/@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {// 声明一个BeanFactoryTransactionAttributeSourceAdvisor对象,// 传入的transactionAttributeSource为AnnotationTransactionAttributeSourceBeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource());advisor.setAdvice(transactionInterceptor());if (this.enableTx != null) {advisor.setOrder(this.enableTx.<Integer>getNumber("order"));}return advisor;}/*** 创建一个AnnotationTransactionAttributeSource对象,该继承AbstractFallbackTransactionAttributeSource,* 对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}/*** 创建一个TransactionInterceptor对象* @return*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource());if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}}
在ProxyTransactionManagementConfiguration中,自动注入了BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource和TransactionInterceptor。添加了事务处理的advisor,该advisor生效时,会执行TransactionInterceptor拦截器。
BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisor的源码如下:
package org.springframework.transaction.interceptor;/*** 继承AbstractBeanFactoryPointcutAdvisor,重写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut* 1、维护TransactionAttributeSource对象;* 2、创建一个TransactionAttributeSourcePointcut,重写getTransactionAttributeSource(),返回TransactionAttributeSource对* 象给TransactionAttributeSourcePointcut,进行方法事务注解判断*/
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {// 在ProxyTransactionManagementConfiguration类中的transactionAdvisor()方法,// 设置transactionAttributeSource为AnnotationTransactionAttributeSource@Nullableprivate TransactionAttributeSource transactionAttributeSource;private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {@Override@Nullableprotected TransactionAttributeSource getTransactionAttributeSource() {return transactionAttributeSource;}};public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {this.transactionAttributeSource = transactionAttributeSource;}public void setClassFilter(ClassFilter classFilter) {this.pointcut.setClassFilter(classFilter);}@Overridepublic Pointcut getPointcut() {return this.pointcut;}}
在BeanFactoryTransactionAttributeSourceAdvisor切面中,切点为自定义的实现抽象类TransactionAttributeSourcePointcut的对象,抽象方法getTransactionAttributeSource()返回的TransactionAttributeSource对象为ProxyTransactionManagementConfiguration的transactionAdvisor()方法传入的AnnotationTransactionAttributeSource对象。
TransactionAttributeSourcePointcut
TransactionAttributeSourcePointcut的源码如下:
package org.springframework.transaction.interceptor;/*** 抽象类,继承StaticMethodMatcherPointcut,属于静态的方法匹配。在方法匹配中,通过抽象方法getTransactionAttributeSource()获* 取TransactionAttributeSource对象,然后执行TransactionAttributeSource.getTransactionAttribute(),判断方法是否有事务注解,* 如果有,表示匹配;没有则不匹配*/
@SuppressWarnings("serial")
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {@Overridepublic boolean matches(Method method, @Nullable Class<?> targetClass) {if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {return false;}// 返回AnnotationTransactionAttributeSourceTransactionAttributeSource tas = getTransactionAttributeSource();// 在AnnotationTransactionAttributeSource的getTransactionAttribute()方法中,// 获取方法添加的@Transactional注解的信息,如果没有添加@Transactional注解,返回nullreturn (tas == null || tas.getTransactionAttribute(method, targetClass) != null);}@Overridepublic boolean equals(Object other) {if (this == other) {return true;}if (!(other instanceof TransactionAttributeSourcePointcut)) {return false;}TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());}@Overridepublic int hashCode() {return TransactionAttributeSourcePointcut.class.hashCode();}@Overridepublic String toString() {return getClass().getName() + ": " + getTransactionAttributeSource();}/*** 抽象方法,获得一个TransactionAttributeSource对象* @return*/@Nullableprotected abstract TransactionAttributeSource getTransactionAttributeSource();}
TransactionAttributeSourcePointcut继承StaticMethodMatcherPointcut,StaticMethodMatcherPointcut的类匹配默认为ClassFilter.TRUE,即匹配所有的类。
当Spring中的bean对象声明之后,都会调用BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bean的方法,执行切点的matches(Method method, @Nullable Class<?> targetClass)方法,该方法执行如下:
6.1)调用getTransactionAttributeSource(),获取一个TransactionAttributeSource。此处为AnnotationTransactionAttributeSource对象;
6.2)因为TransactionAttributeSource对象不为空,所以执行TransactionAttributeSource的getTransactionAttribute()方法,该方法会执行AnnotationTransactionAttributeSource的父类AbstractFallbackTransactionAttributeSource的getTransactionAttribute()方法,如果方法有返回值,则matches()方法返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;
在该方法中,最终会调用子类AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务的解析器,从解析器中获取事务属性信息;结合1)中的描述,会解析org.springframework.transaction.annotation包和javax.transaction包下的@Transactional注解。如果没有@Transactional注解,getTransactionAttribute()最终返回null。matches()会返回false,即不支持,如果有注解,则返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;
AnnotationTransactionAttributeSource
AnnotationTransactionAttributeSource的相关源码如下:
package org.springframework.transaction.annotation;/*** 继承AbstractFallbackTransactionAttributeSource,对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息* 1、添加不同类型的事务注解解析器,用于解析注解信息。支撑jta、ejb和spring的事务*/
@SuppressWarnings("serial")
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSourceimplements Serializable {/** 判断包中是否有javax.transaction.Transactional这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */private static final boolean jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", AnnotationTransactionAttributeSource.class.getClassLoader());/** 判断包中是否有javax.ejb.TransactionAttribute这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */private static final boolean ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", AnnotationTransactionAttributeSource.class.getClassLoader());/** 标记是否只有public方法才可以添加事务,默认为true */private final boolean publicMethodsOnly;private final Set<TransactionAnnotationParser> annotationParsers;public AnnotationTransactionAttributeSource() {this(true);}/*** 设置publicMethodsOnly的值,并添加事务的注解解析器集合*/public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {this.publicMethodsOnly = publicMethodsOnly;if (jta12Present || ejb3Present) {this.annotationParsers = new LinkedHashSet<>(4);// 添加spring的Transactional注解解析器this.annotationParsers.add(new SpringTransactionAnnotationParser());// 根据条件,添加jta和ejb3两种事务的注解解析器if (jta12Present) {this.annotationParsers.add(new JtaTransactionAnnotationParser());}if (ejb3Present) {this.annotationParsers.add(new Ejb3TransactionAnnotationParser());}}else {// 如果不支持jta和ejb3两种注解的事务,则只添加spring的Transactional注解解析器this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());}}/*** 调用determineTransactionAttribute()方法,从类中查找事务注解信息*/@Override@Nullableprotected TransactionAttribute findTransactionAttribute(Class<?> clazz) {return determineTransactionAttribute(clazz);}/*** 调用determineTransactionAttribute()方法,从方法中查找事务注解信息*/@Override@Nullableprotected TransactionAttribute findTransactionAttribute(Method method) {return determineTransactionAttribute(method);}/*** 确定事务属性。遍历事务解析器集合,对当前element进行解析,如果能够正常解析,则返回对应* 的TransactionAttribute【RuleBasedTransactionAttribute对象】;否则返回null*/@Nullableprotected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {for (TransactionAnnotationParser annotationParser : this.annotationParsers) {TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);if (attr != null) {return attr;}}return null;}}
在AnnotationTransactionAttributeSource构造方法中,会添加SpringTransactionAnnotationParser和JtaTransactionAnnotationParser事务注解解析器。
7.1 SpringTransactionAnnotationParser
SpringTransactionAnnotationParser的源码如下:
package org.springframework.transaction.annotation;
/*** 实现TransactionAnnotationParser,解析org.springframework.transaction.annotation.Transactional的注解信息,* 返回一个RuleBasedTransactionAttribute对象*/
@SuppressWarnings("serial")
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {/*** 解析@Transaction注解,获取一个TransactionAttribute对象*/@Override@Nullablepublic TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {// 在所提供的element上方的注释层次结构中查找Transactional的第一个注释,// 并将该注释的属性与注释层次结构较低级别注释中的匹配的attribute合并AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(element, Transactional.class, false, false);// 解析Transactional注解,返回一个RuleBasedTransactionAttribute对象if (attributes != null) {return parseTransactionAnnotation(attributes);}else {return null;}}public TransactionAttribute parseTransactionAnnotation(Transactional ann) {return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));}/*** 从注解属性对象中,获取事务注解相关属性信息,封装成RuleBasedTransactionAttribute对象*/protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {// 根据注解的信息,创建一个RuleBasedTransactionAttribute对象RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();Propagation propagation = attributes.getEnum("propagation");rbta.setPropagationBehavior(propagation.value());Isolation isolation = attributes.getEnum("isolation");rbta.setIsolationLevel(isolation.value());rbta.setTimeout(attributes.getNumber("timeout").intValue());rbta.setReadOnly(attributes.getBoolean("readOnly"));rbta.setQualifier(attributes.getString("value"));// 添加回滚规则List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {rollbackRules.add(new RollbackRuleAttribute(rbRule));}for (String rbRule : attributes.getStringArray("rollbackForClassName")) {rollbackRules.add(new RollbackRuleAttribute(rbRule));}for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {rollbackRules.add(new NoRollbackRuleAttribute(rbRule));}for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {rollbackRules.add(new NoRollbackRuleAttribute(rbRule));}rbta.setRollbackRules(rollbackRules);return rbta;}@Overridepublic boolean equals(Object other) {return (this == other || other instanceof SpringTransactionAnnotationParser);}@Overridepublic int hashCode() {return SpringTransactionAnnotationParser.class.hashCode();}}
SpringTransactionAnnotationParser用于解析org.springframework.transaction.annotation包下的@Transactional的注解信息。
7.2 JtaTransactionAnnotationParser
JtaTransactionAnnotationParser的源码如下:
package org.springframework.transaction.annotation;/*** 实现TransactionAnnotationParser,用于解析javax.transaction.Transactional注解的事务属性。返回一个RuleBasedTransactionAttribute对象*/
@SuppressWarnings("serial")
public class JtaTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {/*** 判断是否有javax.transaction.Transactional,如果有,则进行注解解析【解析传播行为,回滚的异常类、不回滚的异常类设置回滚规则】,* 返回一个RuleBasedTransactionAttribute对象* @param element* @return*/@Override@Nullablepublic TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(element, javax.transaction.Transactional.class);if (attributes != null) {return parseTransactionAnnotation(attributes);}else {return null;}}public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));}protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();// 通过注解的value设定传播行为。默认为REQUIREDrbta.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());// 根据设置的回滚的异常类,添加回滚规则List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();for (Class<?> rbRule : attributes.getClassArray("rollbackOn")) {rollbackRules.add(new RollbackRuleAttribute(rbRule));}// 根据设置的不回滚的异常类,添加回滚规则,定义为不回滚for (Class<?> rbRule : attributes.getClassArray("dontRollbackOn")) {rollbackRules.add(new NoRollbackRuleAttribute(rbRule));}rbta.setRollbackRules(rollbackRules);return rbta;}@Overridepublic boolean equals(Object other) {return (this == other || other instanceof JtaTransactionAnnotationParser);}@Overridepublic int hashCode() {return JtaTransactionAnnotationParser.class.hashCode();}}
JtaTransactionAnnotationParser用于解析javax.transaction包下的@Transactional注解。
在6.2)中调用AnnotationTransactionAttributeSource的getTransactionAttribute(),最终会调用AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务注解的解析器,从解析器中获取事务属性信息。只要方法中添加了org.springframework.transaction.annotation包或javax.transaction包的@Transactional注解,则能够正常获取事务属性信息。
小结
限于篇幅,本篇先分享到这里。以下做一个小结:
1)在SpringBoot框架的项目,项目启动时,会自动开启@EnableTransactionManagement注解,从而自动添加BeanFactoryTransactionAttributeSourceAdvisor切面,添加TransactionAttributeSourcePointcut切点。该切点的ClassFilter为ClassFilter.TRUE,即过滤所有的类。
2)Spring的bean自动注入时,会执行BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bena的方法,执行TransactionAttributeSourcePointcut的matches()。在该方法中,会执行AnnotationTransactionAttributeSource的getTransactionAttribute()方法,判断方法是否添加了org.springframework.transaction.annotation包或javax.transaction包下的@Transactional注解,如果有,则bean的代理类中添加TransactionInterceptor拦截器;
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。
相关文章:

【源码】SpringBoot事务注册原理
前言 对于数据库的操作,可能存在脏读、不可重复读、幻读等问题,从而引入了事务的概念。 事务 1.1 事务的定义 事务是指在数据库管理系统中,一系列紧密相关的操作序列,这些操作作为一个单一的工作单元执行。事务的特点是要么全…...

技巧:合并ZIP分卷压缩包
如果ZIP压缩文件文件体积过大,大家可能会选择“分卷压缩”来压缩ZIP文件,那么,如何合并zip分卷压缩包呢?今天我们分享两个ZIP分卷压缩包合并的方法给大家。 方法一: 我们可以将分卷压缩包,通过解压的方式…...

数据挖掘 | 实验三 决策树分类算法
文章目录 一、目的与要求二、实验设备与环境、数据三、实验内容四、实验小结 一、目的与要求 1)熟悉决策树的原理; 2)熟练使用sklearn库中相关决策树分类算法、预测方法; 3)熟悉pydotplus、 GraphViz等库中决策树模型…...

Python机器学习预测区间估计工具库之mapie使用详解
概要 在数据科学和机器学习领域,预测的不确定性估计是一个非常重要的课题。Python的mapie库是一种专注于预测区间估计的工具,旨在提供简单易用的接口来计算和评估预测的不确定性。通过mapie库,用户可以为各种回归和分类模型计算预测区间,从而更好地理解模型预测的可靠性。…...

Linux基础指令磁盘管理002
LVM(Logical Volume Manager)是Linux系统中一种灵活的磁盘管理和存储解决方案,它允许用户在物理卷(Physical Volumes, PV)上创建卷组(Volume Groups, VG),然后在卷组上创建逻辑卷&am…...

Python怎么添加库:深入解析与操作指南
Python怎么添加库:深入解析与操作指南 在Python编程中,库(Library)扮演着至关重要的角色。它们为我们提供了大量的函数、类和模块,使得我们可以更高效地编写代码,实现各种功能。那么,Python如何…...

Python | 虚拟环境的增删改查
mkvirtualenv创建虚拟环境 mkvirtualenv是用于在Pyhon中创建虚拟环境的命令。它通过使用vitualenv库来创建一个隔离的Python环境,以便您可以安装特定版本的Python包,而不会影响全局Python环境。 使用方法: 安装virtualenv:pip install vir…...

【MySQL数据库】:MySQL内外连接
目录 内外连接和多表查询的区别 内连接 外连接 左外连接 右外连接 简单案例 内外连接和多表查询的区别 在 MySQL 中,内连接是多表查询的一种方式,但多表查询包含的范围更广泛。外连接也是多表查询的一种具体形式,而多表查询是一个更…...

C# FTP/SFTP 详解及连接 FTP/SFTP 方式示例汇总
文章目录 1、FTP/SFTP基础知识FTPSFTP 2、FTP连接示例3、SFTP连接示例4、总结 在软件开发中,文件传输是一个常见的需求。尤其是在不同的服务器之间传输文件时,FTP(文件传输协议)和SFTP(安全文件传输协议)成…...

二、【源码】实现映射器的注册和使用
源码地址:https://github.com/mybatis/mybatis-3/ 仓库地址:https://gitcode.net/qq_42665745/mybatis/-/tree/02-auto-registry-proxy 实现映射器的注册和使用 这一节的目的主要是实现自动注册映射器工厂 流程: 1.创建MapperRegistry注册…...

Android Compose 十:常用组件列表 监听
1 去掉超出滑动区域时的拖拽的阴影 即 overScrollMode 代码如下 CompositionLocalProvider(LocalOverscrollConfiguration provides null) {LazyColumn() {items(list, key {list.indexOf(it)}){Row(Modifier.animateItemPlacement(tween(durationMillis 250))) {Text(text…...

Wireshark 如何查找包含特定数据的数据帧
1、查找包含特定 string 的数据帧 使用如下指令: 双引号中所要查找的字符串 frame contains "xxx" 查找字符串 “heartbeat” 示例: 2、查找包含特定16进制的数据帧 使用如下指令: TCP:在TCP流中查找 tcp contai…...

【深度学习入门篇一】阿里云服务器(不需要配环境直接上手跟学代码)
前言 博主刚刚开始学深度学习,配环境配的心力交瘁,一塌糊涂,不想配环境的刚入门的同伴们可以直接选择阿里云服务器 阿里云天池实验室,在入门阶段跑个小项目完全没有问题,不要自己傻傻的在那配环境配了半天还不匹配&a…...

app,waf笔记
API攻防 知识点: 1、HTTP接口类-测评 2、RPC类接口-测评 3、Web Service类-测评 内容点: SOAP(Simple Object Access Protocol)简单对象访问协议是交换数据的一种协议规范,是一种轻量级的、简单的、基于XML&#…...

数据仓库之维度建模
维度建模(Dimensional Modeling)是一种用于数据仓库设计的方法,旨在优化查询性能并提高数据的可读性。它通过组织数据为事实表和维度表的形式,提供直观的、易于理解的数据模型,使业务用户能够轻松地进行数据分析和查询…...

解决远程服务器连接报错
最近使用服务器进行数据库连接和使用的时候出现了一个报错: Error response from daemon: Conflict. The container name “/mysql” is already in use by container “1bd3733123219372ea7c9377913da661bb621156d518b0306df93cdcceabb8c4”. You have to remove …...

通过电脑查看Wi-Fi密码的方法,提供三种方式
式一: 右击桌面右下角的网络图标,依次选择【网络和Internet设置】、【WLAN】、【网络和共享中心】。点击已连接的无线网络。依次点击【无线属性】、【安全】,勾选下方【显示字符】即可。 方式二: 在开始菜单输入“cmd”进入命令…...

Nvidia 目前的市值为 3.01 万亿美元,超过苹果Apple
人工智能的繁荣将英伟达的市值推高到足以使其成为全球第二大最有价值的公司。 英伟达已成为全球第二大最有价值的公司。周三下午,这家芯片制造巨头的市值达到 3.01 万亿美元,领先于苹果公司的 3 万亿美元。 喜好儿网AIGC专区:https://heehe…...

用langchain搭配最新模型ollama打造属于自己的gpt
langchain 前段时间去玩了一下langchain,熟悉了一下大模型的基本概念,使用等。前段时间meta的ollama模型发布了3.0,感觉还是比较强大的,在了解过后,自己去用前后端代码,调用ollama模型搭建了一个本地的gpt应用。 核心逻辑 开始搭…...

工业互联网基本概念及关键技术(295页PPT)
资料介绍: 工业互联网的核心是通过工业互联网平台把设备、生产线、工厂、供应商、产品和客户紧密地连接融合起来。这种连接能够形成跨设备、跨系统、跨厂区、跨地区的互联互通,从而提高效率,推动整个制造服务体系智能化。同时,工…...

Python pandas openpyxl excel合并单元格,设置边框,背景色
Python pandas openpyxl excel合并单元格,设置边框,背景色 1. 效果图2. 源码参考 1. 效果图 pandas设置单元格背景色,字体颜色,边框 openpyxl合并单元格,设置丰富的字体 2. 源码 # excel数字与列名互转 import o…...

【vue3|第7期】 toRefs 与 toRef 的深入剖析
日期:2024年6月6日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方ÿ…...

git代码冲突处理软件P4Merge
文章目录 1. 下载安装2. 配置脚本参考链接 1. 下载安装 下载地址:https://www.perforce.com/downloads/helix-visual-client-p4v 下载教程:http://blog.csdn.net/wirelessqa/article/details/9035215 这里下载之前需要注册。 2. 配置脚本 编写一个全局…...

Unity物体材质属性Offset动态偏移
Unity物体材质属性Offset动态偏移 MeshRenderer mr;float offset;public float scrollSpeed 0.5F;private void Start(){mr GetComponent<MeshRenderer>();}void Update(){offset -Time.time * scrollSpeed;mr.material.mainTextureOffset new Vector2(0, -offset);}…...

【数据结构】筛选法建堆
💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…...

DevExpress Installed
一、What’s Installed 统一安装程序将DevExpress控件和库注册到Visual Studio中,并安装DevExpress实用工具、演示应用程序和IDE插件。 Visual Studio工具箱中的DevExpress控件 Visual Studio中的DevExpress菜单 Demo Applications 演示应用程序 Launch the Demo…...

解决QT QMessageBox 弹出需点击两次才能关闭问题
放个链接不迷路:添加链接描述...

Milvus--向量数据库
Milvus 是一个开源的向量数据库,专为高维向量数据的存储、查询和检索而设计。它支持多种类型的向量数据,如浮点数向量、整数向量等,并且提供了强大的向量相似度计算功能。Milvus采用分布式架构,可以轻松地扩展到大规模数据集&…...

php质量工具系列之PHPCPD
PHPCPD 用于检测重复代码,直观的说就是复制粘贴再稍微改改 该工具作者已经 停止维护 安装 composer global require --dev sebastian/phpcpd执行 phpcpd --log-pmd phpcpd_result.xml ./app参数介绍 --log-pmd 将结果保存在phpcpd_result.xml 中 ./app 是phpcpd扫…...

Android14 WMS-窗口绘制之relayoutWindow流程(二)-Server端
本文接着如下文章往下讲 Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端-CSDN博客 然后就到了Server端WMS的核心实现方法relayoutWindow里 WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server…...