当前位置: 首页 > news >正文

spring声明式事务原理01-调用第1层@Transactional方法(事务访问入口)

文章目录

  • 【README】
  • 【步骤1】UserAppService调用userSupport.saveNewUser()
  • 【步骤2】获取到TransactionInterceptor
  • 【步骤3】chain不为空,接着执行CglibMethodInvocation#proceed方法
    • 【补充】AopContext作用
  • 【步骤4】CglibMethodInvocation#proceed方法
  • 【步骤5】调用ReflectiveMethodInvocation#proceed方法(反射方法调用类)
  • 【步骤6】调用 TransactionInterceptor#invoke(事务拦截器#invoke方法)
    • 【补充】TransactionInterceptor-事务拦截器源码
  • 【步骤7】调用TransactionAspectSupport#invokeWithinTransaction方法
  • 【步骤8】根据事务属性txAttr获取事务管理器,tm=JdbcTransactionManager
    • 【补充】事务管理器是什么?
  • 【步骤9】TransactionAspectSupport#invokeWithinTransaction()-在事务中执行业务逻辑(非常重要)
    • 【步骤9.1】按需创建事务-createTransactionIfNecessary()
    • 【补充】TransactionInfo事务信息定义
    • 【补充】TransactionStatus事务状态定义
    • 【步骤9.2】执行目标方法

【README】

1)声明式事务代码样例:

在这里插入图片描述

public interface UserMapper {UserPO qryUserById(@Param("id") String id);@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)void insertUser(UserPO userPO);
}public interface UserAccountMapper {@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)void insertUserAccount(UserAccountPO userAccountPO);
}

【代码解说】

  • 代码调用链路:UserAppService -> userSupport.saveNewUser -> userMapper.insertUser + userAccountMapper.insertUserAccount
  • userSupport.saveNewUser 带有 @Transactional 注解; 第1层(最外层)@Transactional标注的方法
    • userMapper.insertUser 带有 @Transactional 注解; 第2层@Transactional标注的方法1
    • userAccountMapper.insertUserAccount 带有 @Transactional 注解; 第2层@Transactional标注的方法2

2)@Transactional:事务注解,用于定义事务元数据,包括事务管理器名称,事务传播行为,超时时间(单位秒),是否只读,回滚的异常类型;

  • @Transactional可以标注类与方法,不管是标注类还是方法,@Transactional标注所在的类的bean都会被spring通过aop代理进行增强;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Reflective
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";String[] label() default {};Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default -1;String timeoutString() default "";boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}


【步骤1】UserAppService调用userSupport.saveNewUser()

1)因为 userSupport中的saveNewUser方法被@Transaction标注,所以该bean被spring增强为aop代理,所以访问aop代理的入口方法intercept(),即CglibAopProxy#DynamicAdvisedInterceptor静态内部类的 intercept方法;

在这里插入图片描述



【步骤2】获取到TransactionInterceptor

在这里插入图片描述



【步骤3】chain不为空,接着执行CglibMethodInvocation#proceed方法

chain有一个元素: TransactionInterceptor-事务拦截器;

接着执行 467行:retVal = (new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();

在这里插入图片描述


【补充】AopContext作用

【补充455行代码】: AopContext实际上是带有ThreadContext的容器对象,用于存储代理对象;

public final class AopContext {private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal("Current AOP proxy");private AopContext() {}public static Object currentProxy() throws IllegalStateException {Object proxy = currentProxy.get();if (proxy == null) {throw new IllegalStateException("Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.");} else {return proxy;}}@Nullablestatic Object setCurrentProxy(@Nullable Object proxy) {Object old = currentProxy.get();if (proxy != null) {currentProxy.set(proxy);} else {currentProxy.remove();}return old;}
}


【步骤4】CglibMethodInvocation#proceed方法

CglibMethodInvocation#proceed方法, 即Cglib方法调用类#proceed方法 (proceed=继续或进行或处理)

【CglibAopProxy#CglibMethodInvocation】

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method, Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);}// 调用proceed @Nullablepublic Object proceed() throws Throwable {try {return super.proceed();} catch (RuntimeException var2) {throw var2;} catch (Exception var3) {if (!ReflectionUtils.declaresException(this.getMethod(), var3.getClass()) && !KotlinDetector.isKotlinType(this.getMethod().getDeclaringClass())) {throw new UndeclaredThrowableException(var3);} else {throw var3;}}}
}


【步骤5】调用ReflectiveMethodInvocation#proceed方法(反射方法调用类)

调用ReflectiveMethodInvocation#proceed方法, ReflectiveMethodInvocation=反射方法调用类

// ReflectiveMethodInvocation=反射方法调用类
// interceptorsAndDynamicMethodMatcher 是一个列表,包含一个元素 TransactionInterceptor 
// currentInterceptorIndex 初始值=-1 
public Object proceed() throws Throwable {if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return this.invokeJoinpoint();} else {Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// interceptorOrInterceptionAdvice 就是 TransactionInterceptor ,而不是 InterceptorAndDynamicMethodMatcherif (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();return dm.matcher().matches(this.method, targetClass, this.arguments) ? dm.interceptor().invoke(this) : this.proceed();} else {return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this); // 调用到这里 }}
}

在这里插入图片描述

获取到的interceptorOrInterceptionAdvice的属性如下:

在这里插入图片描述



【步骤6】调用 TransactionInterceptor#invoke(事务拦截器#invoke方法)

调用 TransactionInterceptor#invoke(ReflectiveMethodInvocation), 传入的入参this是ReflectiveMethodInvocation-反射方法调用对象(包装了 UserSupportImpl#saveNewUser方法的代理对象)

【TransactionInterceptor#invoke】

public Object invoke(MethodInvocation invocation) throws Throwable {Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;Method var10001 = invocation.getMethod();Objects.requireNonNull(invocation);return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}

上述 invocation::proceed中的invocation实际是 ReflectiveMethodInvocaion-反射方法调用类,ReflectiveMethodInvocaion封装了代理对象proxy,方法method等属性;

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {protected final Object proxy;@Nullableprotected final Object target;protected final Method method;protected Object[] arguments;@Nullableprivate final Class<?> targetClass;@Nullableprivate Map<String, Object> userAttributes;protected final List<?> interceptorsAndDynamicMethodMatchers;private int currentInterceptorIndex = -1;protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {this.proxy = proxy;this.target = target;this.targetClass = targetClass;this.method = BridgeMethodResolver.findBridgedMethod(method);this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;}

【补充】TransactionInterceptor-事务拦截器源码

TransactionInterceptor继承自TransactionAspectSupport;

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {public TransactionInterceptor() {}public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {this.setTransactionManager(ptm);this.setTransactionAttributeSource(tas);}@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;Method var10001 = invocation.getMethod();Objects.requireNonNull(invocation);// 调用到这里, 注意最后一个入参是 invocation::proceed;return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);}private void writeObject(ObjectOutputStream oos) throws IOException {
//...}private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {// ...}
}


【步骤7】调用TransactionAspectSupport#invokeWithinTransaction方法

因为TransactionInterceptor 继承自TransactionAspectSupport; 而invokeWithinTransaction方法的最后一个入参invocation就是封装了目标方法,即UserSupportImpl#saveNewUser方法的包装对象ReflectiveMethodInvocation;

在这里插入图片描述

获取到的事务管理器类型是 JdbcTransactionManger, 而事务属性TransactionAttribute保存了注解@Transaction标注的方法的元数据,包括事务传播行为,隔离级别,超时时间,是否只读,事务管理器等属性; 而TransactionAttribute继承自TransactionDefinition-事务定义接口;

【TransactionAttribute】事务属性-TransactionAttribute定义

public interface TransactionAttribute extends TransactionDefinition {@NullableString getQualifier();Collection<String> getLabels();boolean rollbackOn(Throwable ex);
}

【TransactionAspectSupport#invokeWithinTransaction方法】执行到获取PlatformTransactionManager-平台事务管理器;

在这里插入图片描述



【步骤8】根据事务属性txAttr获取事务管理器,tm=JdbcTransactionManager

上述第7步执行到145行,接着判断tm(也就是JdbcTransactionManager)是否是ReactiveTransactionManager类型;

JdbcTransactionManager父类是DataSourceTransactionManager,而DataSourceTransactionManager父类是AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager父类是PlatformTransactionManager;结论:tm(JdbcTransactionManager)不是CallbackPreferringPlatformTransactionManager,所以执行到160行;

在这里插入图片描述

又160行得到的ptm还是JdbcTransactionManager,与tm指向同一个对象,162行判断是否为CallbackPreferringPlatformTransactionManager类型不通过,接着执行第220行;

【补充】事务管理器是什么?

public class JdbcTransactionManager extends DataSourceTransactionManager;public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean;public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, ConfigurableTransactionManager, Serializable; 

【DataSourceTransactionManager】数据源事务管理器-方法列表

  • doBegin-开启事务
  • doCommit-提交事务
  • doGetTransaction-获取事务
  • doResume-恢复事务
  • doRollback-回滚事务
  • doSuspend-挂起事务;

在这里插入图片描述

【DataSourceTransactionManager父类AbstractPlatformTransactionManager】抽象平台事务管理器-部分方法列表

  • doBegin 开启事务
  • doCommit 提交
  • doGetTransation 获取事务
  • doResume 恢复事务
  • doSuspend 挂起事务
  • doRollback 回滚
  • setNestedTransactionAllowed -设置允许嵌套事务;


【步骤9】TransactionAspectSupport#invokeWithinTransaction()-在事务中执行业务逻辑(非常重要)

1)TransactionAspectSupport#invokeWithinTransaction()-在事务中执行业务逻辑,具体步骤如下(跳过了分支判断):

  • 步骤9.1:调用createTransactionIfNecessary方法,创建事务;
  • 步骤9.2:调用invocation.proceedWithInvocation(),执行具体业务逻辑(执行目标方法);
    • 步骤9.2.1(或有) : 抛出异常,执行completeTransactionAfterThrowing
  • 步骤9.3:执行完成(无论是否抛出异常),调用cleanupTransactionInfo()
  • 步骤9.4:判断返回值是否不为null 且 事务属性是否不为null
  • 步骤9.5:调用commitTransactionAfterReturning(),提交事务;

【TransactionAspectSupport#invokeWithinTransaction()】 在事务中调用;上游是TransactionInterceptor,而TransactionInterceptor是TransactionAspectSupport的子类; 源码如下。

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {TransactionAttributeSource tas = this.getTransactionAttributeSource();TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;TransactionManager tm = this.determineTransactionManager(txAttr);if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {// tm类型是JdbcTransactionManager,所以不会执行到这里// ... return txSupport.invokeWithinTransaction(method, targetClass, invocation, txAttr, rtm);} else {PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);if (txAttr != null && ptm instanceof CallbackPreferringPlatformTransactionManager cpptm) {// ptm类型是JdbcTransactionManager,所以不会执行到这里// ...} else {// 程序执行到这里 // 1 创建事务,【非常重要】 TransactionInfo txInfo = this.createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// 2 通过反射执行具体业务逻辑, invocation就是包装了业务方法UserSuuportImpl#saveUser()方法的调用对象 retVal = invocation.proceedWithInvocation();} catch (Throwable var22) {// 2.1 抛出异常 (或有)this.completeTransactionAfterThrowing(txInfo, var22);throw var22;} finally {// 3 最后清理事务信息 this.cleanupTransactionInfo(txInfo);}// 4 判断返回值是否不为null 且 事务属性是否不为null if (retVal != null && txAttr != null) {TransactionStatus status = txInfo.getTransactionStatus();if (status != null) {label185: {if (retVal instanceof Future) {// 5 若返回值为 Future类型(异步线程执行结果类)Future<?> future = (Future)retVal;if (future.isDone()) {try {future.get();} catch (ExecutionException var27) {if (txAttr.rollbackOn(var27.getCause())) {status.setRollbackOnly();}} catch (InterruptedException var28) {Thread.currentThread().interrupt();}break label185;}}if (vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}}}// 5 提交事务 this.commitTransactionAfterReturning(txInfo);return retVal;}}
}


【步骤9.1】按需创建事务-createTransactionIfNecessary()

TransactionAspectSupport#createTransactionIfNecessary()详情参见 spring声明式事务原理02-调用第1层@Transactional方法-按需创建事务createTransactionIfNecessary
在这里插入图片描述根据事务管理器+事务属性+aop连接点(切点)创建事务,如下:

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {public String getName() {return joinpointIdentification;}};}TransactionStatus status = null;if (txAttr != null) {if (tm != null) {// 通过事务管理器获取事务status = tm.getTransaction((TransactionDefinition)txAttr); } else if (this.logger.isDebugEnabled()) {this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");}}// 准备事务信息TransactionInfo return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}

在这里插入图片描述


【补充】TransactionInfo事务信息定义

1)TransactionInfo是TransactionAspectSupport的 静态内部类,是一个聚合类,封装了事务相关的多个组件:

  • transactionManager:事务管理器(封装了事务提交,回滚功能)
  • TransactionAttribute:事务属性 (@Transaction注解元数据)
  • joinpointIdentification:切点标识(被@Transaction标注的目标方法的全限定名称)
  • TransactionStatus:事务状态 (封装获取事务状态的方法,如是否只读,是否回滚,是否保存点,事务是否完成,当前线程是否存在事务等)
  • oldTransactionInfo-上一个事务信息对象;

其中 oldTransactionInfo-上一个事务信息对象,是bindToThread()方法与restoreThreadLocalStatus() 需要用到的;

protected static final class TransactionInfo {@Nullableprivate final PlatformTransactionManager transactionManager;@Nullableprivate final TransactionAttribute transactionAttribute;private final String joinpointIdentification;@Nullableprivate TransactionStatus transactionStatus;@Nullableprivate TransactionInfo oldTransactionInfo;public TransactionInfo(@Nullable PlatformTransactionManager transactionManager, @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {this.transactionManager = transactionManager;this.transactionAttribute = transactionAttribute;this.joinpointIdentification = joinpointIdentification;}public PlatformTransactionManager getTransactionManager() {Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");return this.transactionManager;}@Nullablepublic TransactionAttribute getTransactionAttribute() {return this.transactionAttribute;}public String getJoinpointIdentification() {return this.joinpointIdentification;}public void newTransactionStatus(@Nullable TransactionStatus status) {this.transactionStatus = status;}@Nullablepublic TransactionStatus getTransactionStatus() {return this.transactionStatus;}public boolean hasTransaction() {return this.transactionStatus != null;}private void bindToThread() {this.oldTransactionInfo = (TransactionInfo)TransactionAspectSupport.transactionInfoHolder.get();TransactionAspectSupport.transactionInfoHolder.set(this);}private void restoreThreadLocalStatus() {TransactionAspectSupport.transactionInfoHolder.set(this.oldTransactionInfo);}    
}// 事务信息持有器(transactionInfoHolder)是一个ThreadLocal对象,
// 用于保存当前事务信息,及上一个事务信息(挂起时),以便恢复上一个事务信息;
private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal("Current aspect-driven transaction");

事务信息持有器(transactionInfoHolder):是一个ThreadLocal对象,用于保存当前事务信息,及上一个事务信息(挂起时),以便恢复上一个事务信息;

【补充】TransactionStatus事务状态定义

1)TransactionStatus继承自 TransactionExecution, SavepointManager

2)TransactionStatus封装了事务状态方法,包括是否有保存点,当前线程是否存在事务,当前线程是否存在新事务,是否只读,设置回滚状态或判断是否回滚,事务是否完成等状态方法;

3)封装的事务方法包括:

  • 保存点相关方法:包括 hasSavepoint , createSavepoint, rollbackToSavepoint, releaseSavepoint
  • 事务相关方法: 包括hasTransaction, isNewTransaction, isReadOnly, setRollbackOnly, isRollbackOnly, isCompleted;
  • 嵌套传播模式相关方法:isNested (嵌套模式底层原理是保存点)
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {default boolean hasSavepoint() {return false;}default void flush() {}
}
// 事务执行 
public interface TransactionExecution {default String getTransactionName() {return "";}default boolean hasTransaction() {return true;}default boolean isNewTransaction() {return true;}default boolean isNested() {return false;}default boolean isReadOnly() {return false;}default void setRollbackOnly() {throw new UnsupportedOperationException("setRollbackOnly not supported");}default boolean isRollbackOnly() {return false;}default boolean isCompleted() {return false;}
}
// 保存点管理器
public interface SavepointManager {Object createSavepoint() throws TransactionException;void rollbackToSavepoint(Object savepoint) throws TransactionException;void releaseSavepoint(Object savepoint) throws TransactionException;
}


【步骤9.2】执行目标方法

1)调用 invocation.proceedWithInvocation() 调用目标方法; invocation的类是 CglibMethodInvocation,即cglib代理方法调用类;

在这里插入图片描述

2)invocation.proceedWithInvocation():调用CglibMethodInvocation#proceed() 方法,又CglibMethodInvocation是封装了目标方法的cglib方法调用代理对象,所以接着会调用目标方法,即UserSupportImpl#saveNewUser()方法;

在这里插入图片描述

3)接着调用父类ReflectiveMethodInvocation的proceed()方法;

在这里插入图片描述

4)接着执行ReflectiveMethodInvocation#invokeJoinpoint方法,如下。

在这里插入图片描述

5)接着执行 AopUtils#invokeJoinpointUsingReflection() 方法

其中 originalMethod.invoke(target, args) 是通过反射调用具体的目标方法;

在这里插入图片描述

相关文章:

spring声明式事务原理01-调用第1层@Transactional方法(事务访问入口)

文章目录 【README】【步骤1】UserAppService调用userSupport.saveNewUser()【步骤2】获取到TransactionInterceptor【步骤3】chain不为空&#xff0c;接着执行CglibMethodInvocation#proceed方法【补充】AopContext作用 【步骤4】CglibMethodInvocation#proceed方法【步骤5】调…...

[MoeCTF 2021]babyRCE

打开题目在线环境可以看到&#xff1a; <?php$rce $_GET[rce]; if (isset($rce)) {if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\|\%|\>|\<|\|\"/i", $rce)) {system($rce);}else {echo "hhhhhhacke…...

【leetcode hot 100 114】二叉树展开为链表

解法一&#xff1a;执行一次先序遍历&#xff0c;把元素放入list中&#xff0c;然后放回root中 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { th…...

嵌入式八股,为什么单片机中不使用malloc函数

1. 资源限制 单片机的内存资源通常非常有限&#xff0c;尤其是RAM的大小可能只有几KB到几十KB。在这种情况下&#xff0c;使用 malloc 进行动态内存分配可能会导致内存碎片化&#xff0c;使得程序在运行过程中逐渐耗尽可用内存。 2. 内存碎片问题 malloc 函数在分配和释放内…...

基于Python的selenium入门超详细教程(第1章)--WebDriver API篇

学习路线 自动化测试介绍及学习路线-CSDN博客 ​自动化测试之Web自动化&#xff08;基于pythonselenium&#xff09;-CSDN博客 参照博文&#xff1a;selenium入门超详细教程——网页自动化操作-CSDN博客 目录 前言 一、WebDriver API介绍 1.1 什么是WebDriver? 1.2 工…...

IIC通信协议详解与STM32实战指南

IIC通信协议详解与STM32实战指南 引言 IIC&#xff08;Inter-Integrated Circuit&#xff09;是Philips公司开发的串行通信协议&#xff0c;广泛应用于传感器、EEPROM、RTC等低速外设的连接。本文深入解析IIC协议原理&#xff0c;并提供基于STM32的GPIO模拟实现方案&#xff…...

【算法】数组、链表、栈、队列、树

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 持续更新中...数组、链表点击消除环形链表环形链表 II 栈、队列树 持续更新中… 数组、链表 点击消除 AB5 点击消除 这个题很容…...

vscode 配置golang开发环境

vscode 配置golang开发环境 在go1.20环境中需要指定工具的安装版本 go install golang.org/x/tools/goplsv0.15.3 go install github.com/go-delve/delve/cmd/dlvv1.21.0使用go Install/Update tool安装工具会报错 go版本太低, 而很多时候为了项目稳定或风险太高, 我们不太希…...

uniapp APP使用web-view内嵌 h5 解决打包发版浏览器有缓存需要清除的问题

1.在当前项目根节点下的public目录下的index.html里面写入禁止缓存的 meta <!-- 解决前端发版缓存问题 start --><meta http-equiv"pragma" content"no-cache"><meta http-equiv"cache-control" content"no-cache, no-stor…...

机器学习与深度学习中模型训练时常用的四种正则化技术L1,L2,L21,ElasticNet

L1正则化和L2正则化是机器学习中常用的两种正则化方法&#xff0c;用于防止模型过拟合。它们的区别主要体现在数学形式、作用机制和应用效果上。以下是详细对比&#xff1a; 1. 数学定义 L1正则化&#xff08;也叫Lasso正则化&#xff09;&#xff1a; 在损失函数中加入权重参…...

LLM自动化评测

使用的数据集&#xff1a;ceval-exam import requests from datasets import load_dataset, concatenate_datasets import re from tqdm import tqdm import re, time, tiktoken, ollama from ollama import ChatResponse from ollama import Optionsdef llm(model, query, te…...

Android 英文文章选词

点击文章中的一个单词&#xff0c;获取它。 通过点击的坐标y来获取行数&#xff0c;通过x坐标获取字符偏移量&#xff0c;向前遍历匹配&#xff0c;向后遍历匹配&#xff0c;匹配不成功则跳出循环。截取开始位置和最后位置的字符串。 主要代码 public String getSelectText…...

56.HarmonyOS NEXT 登录模块开发教程(十):总结与展望

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT 登录模块开发教程&#xff08;十&#xff09;&#xff1a;总结与展望 文章目录 HarmonyOS NEXT 登录模块开发教程&#xff08;十&a…...

【Go每日一练】猜数字游戏

&#x1f47b;创作者&#xff1a;丶重明 &#x1f47b;创作时间&#xff1a;2025年3月16日 &#x1f47b;擅长领域&#xff1a;运维 目录 1.&#x1f636;‍&#x1f32b;️题目&#xff1a;猜数字游戏2.&#x1f636;‍&#x1f32b;️代码开发3.&#x1f636;‍&#x1f32b;…...

论文分享:PL-ALF框架实现无人机低纹理环境自主飞行

在室内仓库、地下隧道等低纹理复杂场景中&#xff0c;无人机依赖视觉传感器进行自主飞行时&#xff0c;往往会遇到定位精度低、路径规划不稳定等难题。针对这一问题&#xff0c;重庆邮电大学计算机学院雷大江教授团队在IEEE Trans期刊上提出了一种新型自主飞行框架&#xff1a;…...

element-plus中Autocomplete自动补全输入框组件的使用

目录 1.基本使用 ①从官网复制如下代码 ②查看运行效果 ③代码解读 2.调用后端接口&#xff0c;动态获取建议数据 结语 1.基本使用 ①从官网复制如下代码 <template> <div><!-- 自动补全输入框 --><el-autocompletev-model"state":fetc…...

【医学影像 AI】大型语言模型生成 ROP 患者信息材料的能力

【医学影像 AI】大型语言模型生成 ROP 患者信息材料的能力 0. 论文简介0.1 基本信息0.2 摘要 1. 引言2. 材料与方法2.1 大语言模型的使用2.2 可读性标准2.3 统计分析 3. 结果3.1 Bezirci-Yılmaz可读性评分3.2 Ateşman可读性评分3.3 全面性评分3.4 准确性评分 4. 讨论4.1 可读…...

(性能测试)性能测试工具 2.jmeter的环境搭建 3jmeter元件和4使用实例 5jmeter元件和参数化

目录 性能测试工具 性能测试工具 jemeter环境搭建 jmeter的常用目录介绍 jmeter修改语言和主题--jmeter界面的汉化 jmeter元件 jmeter元件和组件的介绍 jmeter的作用域原则 jmeter的执行顺序 案例&#xff1a;执行顺序 jmeter使用案例 jmeter线程组的介绍 jmeter…...

Matlab 四分之一车体车辆半主动悬架鲁棒控制

1、内容简介 略 Matlab 173-四分之一车体车辆半主动悬架鲁棒控制 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...

Kafka可视化工具KafkaTool工具的使用

Kafka Tool工具 介绍 使用Kafka的小伙伴&#xff0c;有没有为无法直观地查看 Kafka 的 Topic 里的内容而发过愁呢&#xff1f;下面推荐给大家一款带有可视化页面的Kafka工具&#xff1a;Kafka Tool &#xff08;目前最新版本是 3.0.2&#xff09; 注意&#xff1a;以前叫Kafk…...

【Unity】在项目中使用VisualScripting

1. 在packagemanager添加插件 2. 在设置中进行初始化。 Edit > Project Settings > Visual Scripting Initialize Visual Scripting You must select Initialize Visual Scripting the first time you use Visual Scripting in a project. Initialize Visual Scripting …...

【Maven教程与实战案例】

文章目录 前言一、Maven是什么&#xff1f;二、Maven的安装与配置1. 安装前置条件2. 下载与配置 Maven3. 验证安装 三、Maven的核心概念1. POM.xml 文件2. 构建生命周期与插件机制 四、实战项目示例1. 项目目录结构2. 编写代码App.javaAppTest.java 3. 构建项目4. 运行项目 前言…...

Flask中使用with语句手动加载应用上下文

在 Flask 中&#xff0c;with app.app_context(): 手动加载应用上下文&#xff0c;使代码块可以访问 Flask 全局对象&#xff08;如 current_app、g&#xff09;&#xff0c;即使代码不在请求中运行。 1. 为什么需要手动加载应用上下文&#xff1f; 在 Flask 中&#xff0c;某…...

ROS实践(五)机器人自动导航(robot_navigation)

目录 一、知识点 1. 定位 2. 路径规划 (1)全局路径规划 (2)局部路径规划 3. 避障 二、常用工具和传感器 三、相关功能包 1. move_base(决策规划) 2. amcl(定位) 3. costmap_2d(代价地图) 4. global_planner(全局规划器) 5. local_planner(局部规划器…...

【数学建模】层次分析法(AHP)详解及其应用

层次分析法(AHP)详解及其应用 引言 在现实生活和工作中&#xff0c;我们经常面临复杂的决策问题&#xff0c;这些问题通常涉及多个评价准则&#xff0c;且各准则之间可能存在相互影响。如何在这些复杂因素中做出合理的决策&#xff1f;层次分析法(Analytic Hierarchy Process…...

【大模型】Transformer、GPT1、GPT2、GPT3、BERT 的论文解析

前言 在自然语言处理&#xff08;NLP&#xff09;和深度学习的快速发展中&#xff0c;Transformer模型和 GPT系列模型扮演了至关重要的角色。本篇博客旨在对这些开创性的论文进行介绍&#xff0c;涵盖它们的提出时间、网络结构等关键信息&#xff0c;能够快速的理解这些模型的设…...

Android 手机启动过程

梳理 为了梳理思路&#xff0c;笔者画了一幅关于 Android 手机启动的过程图片内容纯属个人见解&#xff0c;如有错误&#xff0c;欢迎各位指正...

【redis】hash基本命令和内部编码

文章目录 表示形式命令HSET 和 HGET HEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSETNXHINCRBYHINCRBYFLOAT命令小结内部编码 表示形式 Redis 自身已经是键值对结构了 Redis 自身的键值对就是通过哈希的方式来组织的 把 key 这一层组织完成之后&#xff0c;到了 value 这一层&…...

统计数字字符个数(信息学奥赛一本通-1129)

【题目描述】 输入一行字符&#xff0c;统计出其中数字字符的个数。 【输入】 一行字符串&#xff0c;总长度不超过255。 【输出】 输出为1行&#xff0c;输出字符串里面数字字符的个数。 【输入样例】 Peking University is set up at 1898. 【输出样例】 4 【输出样例】 #in…...

基于javaweb的SSM+Maven网上选课管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...

算法及数据结构系列 - BFS算法

文章目录 框架思路经典题型111. 二叉树的最小深度752. 打开转盘锁 框架思路 BFS 的核心思想应该不难理解的&#xff0c;就是把一些问题抽象成图&#xff0c;从一个点开始&#xff0c;向四周开始扩散。一般来说&#xff0c;我们写 BFS 算法都是用队列这种数据结构&#xff0c;每…...

深入剖析 MetaSpace OOM 问题:根因分析与高效解决策略

目录 一、MetaSpace 区 OOM&#xff1a;概述 &#xff08;一&#xff09; MetaSpace的变革与挑战 &#xff08;二&#xff09;MetaSpace OOM的影响 &#xff08;三&#xff09; 为什么要关注MetaSpace OOM 二、MetaSpace 区 OOM的根本原因 &#xff08;一&#xff09;Met…...

java自带日志系统介绍(JUL)以及和Log4j 2、Logback、SLF4J不同日志工具的对比

Java 日志系统是开发中用于记录应用程序运行时信息的重要工具。以下是 Java 日志系统的核心组件及其使用场景、配置参数的详细介绍&#xff0c;以及不同日志系统的对比分析。 Java 日志系统核心组件 1. 日志记录器&#xff08;Logger&#xff09; 作用&#xff1a;负责生成日…...

Kubernetes 中metrics-server的采集周期,采集链路是什么样的?

0. 运维干货分享 软考高级系统架构设计师备考学习资料软考高级网络规划设计师备考学习资料Kubernetes CKA认证学习资料分享信息安全管理体系&#xff08;ISMS&#xff09;制度模板分享免费文档翻译工具(支持word、pdf、ppt、excel)PuTTY中文版安装包MobaXterm中文版安装包ping…...

一分钟了解深度学习

一分钟了解深度学习 A Minute to Know About Deep Learning By JacksonML 1. 什么是深度学习&#xff1f; 深度学习(Deep Learning) 是机器学习的一个子集&#xff0c;都属于人工智能的范畴&#xff1b;它使用多层神经网络&#xff08;称为深度神经网络&#xff09;来模拟人…...

Git LFS (Large File Storage) 简介

目录 Git LFS (Large File Storage) 简介 1. 什么是 Git LFS&#xff1f; 2. 为什么需要 Git LFS&#xff1f; 3. Git LFS 的工作原理 4. 如何使用 Git LFS&#xff1f; 4.1 安装 Git LFS 4.2 配置 Git LFS 5. Git LFS 的优缺点 优点 缺点 6. 适用场景 7. 结论 1. …...

前端权限系统

前端权限系统是为了确保用户只能访问他们有权限查看的资源而设计的。在现代前端开发中&#xff0c;权限控制不仅仅是简单的显示或隐藏元素&#xff0c;还涉及到对路由、组件、数据和操作权限的细致控制。下面是前端权限系统的常见设计方案和实现步骤。 前端权限系统的组成部分 …...

【蓝桥杯速成】| 4.递归

递归 题目一&#xff1a;最大公约数 问题描述 1979. 找出数组的最大公约数 - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums &#xff0c;返回数组中最大数和最小数的 最大公约数 。 两个数的 最大公约数 是能够被两个数整除的最大正整数。 解题步骤 需要…...

QEMU源码全解析 —— 块设备虚拟化(4)

接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(3) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 类模板是创建类的模式_创建类是的模版-CSDN博客<...

92.HarmonyOS NEXT开发学习路径与最佳实践总结:构建高质量应用

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT开发学习路径与最佳实践总结&#xff1a;构建高质量应用 文章目录 HarmonyOS NEXT开发学习路径与最佳实践总结&#xff1a;构建高质…...

【004】deepseek本地化部署后,python的调用方式_#py

python调用本地deepseek 1 本地化部署deepseek2 python调用方式 1 本地化部署deepseek 已经有很多大佬们说了不少部署本地化部署deepseek的工作了&#xff0c;我就不过多重复了。 先安装Ollama软件&#xff0c;再通过Ollama获取deepseek的模型文件&#xff0c;大家根据电脑的配…...

基于Python+Flask+MySQL+HTML的爬取豆瓣电影top-250数据并进行可视化的数据可视化平台

FlaskMySQLHTML 项目采用前后端分离技术&#xff0c;包含完整的前端&#xff0c;以flask作为后端 Pyecharts、jieba进行前端图表展示 通过MySQL收集格列数据 通过Pyecharts制作数据图表 这是博主b站发布的详细讲解&#xff0c;感兴趣的可以去观看&#xff1a;【Python爬虫可…...

【Prometheus01】可观测性系统之Prometheus简介、优缺点对比、组件介绍、数据采集流程、TSDB简介

监控工具对比、黑盒监控与盒白盒监控、Kubernetes监控简介 监控简介&#xff1a; 监控的价值&#xff1a; 长期趋势分析&#xff1a;通过对监控样本数据的持续收集和统计&#xff0c;对监控指标进行长期趋势分析。例如&#xff0c;通过对磁盘空间增长率的判断&#xff0c;我们…...

Postman下载安装及简单入门

一&#xff0e;Postman简介 Postman是一款API测试工具&#xff0c;可以帮助开发、测试人员发送HTTP请求&#xff0c;与各种API进行交互&#xff0c;并分析响应 二&#xff0e;下载与安装 访问Postman官网&#xff08;https://www.postman.com/&#xff09;&#xff0c;下载适…...

记第一次跟踪seatunnel的任务运行过程三——解析配置的具体方法getLogicalDag

前绪 记第一次跟踪seatunnel的任务运行过程二——ClientJobExecutionEnvironment的execture方法 从这里开始&#xff0c;就是使用seatunnel-2.3.9的源码了。前面部分没有变化&#xff0c;2.3.X版本都是通用的。 建议打开源码&#xff0c;边读文章&#xff0c;边阅读源码 正文…...

Maven 的核心包

由于前端项目不是核心&#xff0c;阅读 nexus-public 源代码似乎绕远路了。nexus-oss 社区版主要就是集成 maven 的上传包、认证、包解析、包存储这几个核心功能&#xff0c;前端实现重新可以使用新的现代前端工具来提高生产力。故重新疏理一下 maven 的核心机制&#xff0c;即…...

上位机数据可视化:使用QtCharts绘制波形图

工程配置 CMake文件 find_package(Qt5 COMPONENTS Charts REQUIRED)target_link_libraries(zhd-desktop PRIVATE Qt5::Charts)包含头文件以及名称空间&#xff08;这个很重要&#xff0c;没有包含名称空间编译器会提示找不到相关的类型&#xff09; #include <QtCharts&g…...

制造业数字化转型,汽车装备制造企业数字化转型案例,智能制造数字化传统制造业数字化制造业数字化转型案例

《某制造业企业信息化整体解决方案》PPT展示了一个汽车装备企业的整体信息化解决方案&#xff0c;阐述了该企业的业务特点和现状&#xff0c;主要包括按订单生产、多级计划和产品跟踪等&#xff0c;分析了信息化建设的主要困难&#xff0c;如信息管理手工化、过程数据追溯困难、…...

网络安全常识科普(百问百答)

汪乙己一到店&#xff0c;所有喝酒的人便都看着他笑&#xff0c;有的叫道&#xff0c;“汪乙己&#xff0c;你又监控员工隐私了&#xff01;”他不回答&#xff0c;对柜里说&#xff0c;“来两个fofa。”便排出三个比特币。他们又故意的高声嚷道&#xff0c;“你一定又在电报群…...

P2512糖果传递 P4447分组 P1080国王游戏 P4053建筑抢修

P2512 [HAOI2008] 糖果传递 题目描述 有 n n n 个小朋友坐成一圈&#xff0c;每人有 a i a_i ai​ 个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为 1 1 1。 输入格式 小朋友个数 n n n&#xff0c;下面 n n n 行 a i a_i ai​。 输出格式 求使所…...