Spring高手之路26——全方位掌握事务监听器

文章目录

  • 1. 什么是Spring事务监听器?
  • 2. 通过TransactionSynchronization 接口实现事务监听器
  • 3. 时序图:通过TransactionSynchronization 接口实现事务监听器
  • 4. @TransactionalEventListener注解实现事务监听器
  • 5. 时序图:@TransactionalEventListener注解实现事务监听器
  • 6. 实际应用场景

1. 什么是Spring事务监听器?

  Spring事务监听器是一种机制,允许我们在事务的不同阶段(如提交、回滚、开始)执行自定义逻辑。通过事务监听器,我们可以在事务的生命周期中插入一些额外的操作,比如记录日志、发送通知、更新缓存等。

2. 通过TransactionSynchronization 接口实现事务监听器

  在Spring中,事务监听器的设计主要通过实现 TransactionSynchronization 接口并将其注册到当前事务中来实现。这允许在事务的不同阶段(如提交前、提交后、回滚后等)执行特定的逻辑,从而增强事务处理的灵活性和可控性。

核心组件

  1. TransactionSynchronization 接口:这是一个监听器接口,用于接收事务同步事件。该接口提供了多个回调方法,允许我们在事务的不同阶段执行操作。

  2. TransactionSynchronizationManager 类:这是事务同步管理器,负责管理事务同步的回调。

TransactionSynchronization 接口的方法

TransactionSynchronization 接口定义了以下方法:

  • void suspend(): 事务挂起时调用。
  • void resume(): 事务恢复时调用。
  • void flush(): 事务刷新时调用。
  • void beforeCommit(boolean readOnly): 事务提交前调用。
  • void beforeCompletion(): 事务完成前调用。
  • void afterCommit(): 事务提交后调用。
  • void afterCompletion(int status): 事务完成后调用。

接下来,用完整的代码给大家展示这些方法的调用时机

还是用上一篇相近的例子,全部代码如下:

配置类

AppConfig类配置了数据源、SqlSessionFactorySqlSessionTemplate和事务管理器。

package com.example.demo.configuration;import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration
@ComponentScan(basePackages = "com.example.demo")
@MapperScan("com.example.demo.mapper")
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class AppConfig {@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/demo");dataSource.setUsername("root");dataSource.setPassword("password");return dataSource;}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/**/*.xml"));return sqlSessionFactoryBean.getObject();}@Beanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

自定义事务同步处理类

  CustomTransactionSynchronization类实现了TransactionSynchronization接口,用于在事务的不同阶段执行特定的逻辑。该接口定义了多个回调方法,每个方法中都加入了日志输出,方便我们了解事务的状态变化。

package com.example.demo.listener;import org.springframework.transaction.support.TransactionSynchronization;/*** 自定义事务同步处理类,实现 TransactionSynchronization 接口* 用于在事务的不同阶段执行特定的逻辑。*/
public class CustomTransactionSynchronization implements TransactionSynchronization {/*** 事务挂起时调用的方法。*/@Overridepublic void suspend() {// 输出事务挂起的日志System.out.println("Transaction suspended");}/*** 事务恢复时调用的方法。*/@Overridepublic void resume() {// 输出事务恢复的日志System.out.println("Transaction resumed");}/*** 事务刷新时调用的方法。*/@Overridepublic void flush() {// 输出事务刷新的日志System.out.println("Transaction flushed");}/*** 事务提交前调用的方法。* readOnly 参数是一个布尔值,指示当前事务是否为只读事务。true表示当前事务为只读事务,false表示当前事务为读写事务。* @param readOnly 是否为只读事务*/@Overridepublic void beforeCommit(boolean readOnly) {// 输出事务提交前的日志,显示是否为只读事务System.out.println("Transaction before commit, readOnly: " + readOnly);}/*** 事务完成前调用的方法。*/@Overridepublic void beforeCompletion() {// 输出事务完成前的日志System.out.println("Transaction before completion");}/*** 事务提交后调用的方法。*/@Overridepublic void afterCommit() {// 输出事务提交后的日志System.out.println("Transaction after commit");}/*** 事务完成后调用的方法。** @param status 事务完成的状态,STATUS_COMMITTED 或 STATUS_ROLLED_BACK*/@Overridepublic void afterCompletion(int status) {// 根据事务完成的状态输出相应的日志if (status == TransactionSynchronization.STATUS_COMMITTED) {// 事务成功提交System.out.println("Transaction completed with status: COMMITTED");} else if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {// 事务回滚System.out.println("Transaction completed with status: ROLLED_BACK");}}
}

Mapper接口

TestMapper接口定义了插入Test对象的方法。

package com.example.demo.mapper;import com.example.demo.model.Test;public interface TestMapper {// 定义插入Test的方法void insertTest(Test test);
}

MyBatis Mapper XML文件

MyBatis Mapper XML文件定义了插入Test记录的SQL语句。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.TestMapper"><!-- 插入记录到test表 --><insert id="insertTest" parameterType="com.example.demo.model.Test">INSERT INTO test (name) VALUES (#{name})</insert>
</mapper>

Model类

package com.example.demo.model;// 定义Test类与数据库表test对应
public class Test {private Long id; // 主键IDprivate String name; // 名称// 获取IDpublic Long getId() {return id;}// 设置IDpublic void setId(Long id) {this.id = id;}// 获取名称public String getName() {return name;}// 设置名称public void setName(String name) {this.name = name;}
}

服务类

TestService类包含一个事务性的方法createTest,该方法在插入记录前后注册自定义的事务同步处理类。

package com.example.demo.service;import com.example.demo.listener.CustomTransactionSynchronization;
import com.example.demo.mapper.TestMapper;
import com.example.demo.model.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;@Service
public class TestService {@Autowired // 注入 TestMapperprivate TestMapper testMapper;// 使用自定义的 @MyTransactional 注解@Transactionalpublic void createTest(Test test) {System.out.println("createTest is called.");CustomTransactionSynchronization synchronization = new CustomTransactionSynchronization();TransactionSynchronizationManager.registerSynchronization(synchronization);testMapper.insertTest(test); // 插入记录// 模拟异常以测试事务回滚if ("error".equals(test.getName())) {throw new RuntimeException("Simulated error");}System.out.println("createTest is finished.");}
}

主程序类

package com.example.demo;import com.example.demo.configuration.AppConfig;
import com.example.demo.model.Test;
import com.example.demo.service.TestService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class DemoApplication {public static void main(String[] args) {// 加载 Spring 配置文件ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取 TestService BeanTestService testService = context.getBean(TestService.class);try {Test test = new Test();test.setName("success");testService.createTest(test);System.out.println("Test with name 'success' created.");} catch (Exception e) {System.out.println("Failed to create test with name 'success': " + e.getMessage());}System.out.println("======================");try {Test test = new Test();test.setName("error");testService.createTest(test);} catch (Exception e) {System.out.println("Failed to create test with name 'error': " + e.getMessage());}}
}

运行结果:

在这里插入图片描述

打印日志的配置如下,方便大家运行调试

<configuration><!-- 定义控制台日志输出 --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 设置全局日志级别为 INFO --><root level="INFO"><appender-ref ref="console" /></root><!-- 设置特定包的日志级别 --><logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager" level="INFO" /><logger name="org.mybatis.spring.SqlSessionUtils" level="INFO" /><logger name="com.example.demo.mapper" level="DEBUG" />
</configuration>

3. 时序图:通过TransactionSynchronization 接口实现事务监听器

在这里插入图片描述

时序图中各个步骤的详细解释:

  1. 调用业务方法:
  • 客户端调用业务服务的方法,开始事务性操作。
  1. 开启事务:
  • 业务服务向事务管理器发起请求,开启一个新的事务。
  1. 注册同步处理器:
  • 事务管理器注册事务监听器,这一步使得监听器能够在事务的不同阶段接收通知和执行特定操作。
  1. 事务开始:
  • 事务监听器记录事务的开始,此时可以进行一些初始化操作。
  1. 执行业务逻辑:
  • 业务服务执行业务逻辑,比如数据库操作等,并返回结果。
  1. 事务提交前:
  • 在事务提交之前,事务管理器调用事务监听器的 beforeCommit(boolean readOnly) 方法。这个方法允许我们在提交之前执行一些操作,如检查事务状态。
  1. 事务完成前:
  • 在事务完成之前,无论是提交还是回滚,事务管理器都会调用事务监听器的 beforeCompletion() 方法。这一步通常用于执行一些清理工作。
  1. 提交事务或回滚事务:
  • 事务管理器决定提交事务还是回滚事务。
  • 如果提交事务,事务管理器会先调用事务监听器的 afterCommit() 方法,随后调用 afterCompletion(STATUS_COMMITTED) 方法,表示事务成功提交。
  • 如果回滚事务,事务管理器直接调用事务监听器的 afterCompletion(STATUS_ROLLED_BACK) 方法,表示事务已经回滚。
  1. 业务方法完成:
  • 客户端收到业务方法执行完成的通知。
  1. 事务刷新:
  • 在某些情况下,事务管理器可能会调用事务监听器的 flush() 方法,强制刷新事务中的某些操作。
  1. 事务挂起:
  • 事务管理器调用事务监听器的 suspend() 方法,事务进入挂起状态,这可能发生在嵌套事务的场景中。
  1. 事务恢复:
  • 事务管理器调用事务监听器的 resume() 方法,恢复挂起的事务。

4. @TransactionalEventListener注解实现事务监听器

  除了实现TransactionSynchronization接口,我们还可以通过@TransactionalEventListener注解来实现事务监听器。这种方式需要事件被发布才能被监听到。

我们在上一小节代码的基础上修改一下。

1.新增自定义事务事件类CustomTransactionEvent

CustomTransactionEvent类是一个简单的事件类,包含事件类型的字段。

package com.example.demo.event;/*** 自定义事务事件类。*/
public class CustomTransactionEvent {private final String eventType; // 事件类型/*** 构造函数。** @param eventType 事件类型*/public CustomTransactionEvent(String eventType) {this.eventType = eventType;}/*** 获取事件类型。** @return 事件类型*/public String getEventType() {return eventType;}
}

2. 新增自定义事务事件监听器TransactionEventListener

TransactionEventListener类使用@TransactionalEventListener注解监听事务事件,并根据事件类型在不同阶段执行操作。

package com.example.demo.listener;import com.example.demo.event.CustomTransactionEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;/*** 自定义事务事件监听器。*/
@Component
public class TransactionEventListener {/*** 处理事务提交前事件。** @param event 自定义事务事件*/@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)public void beforeCommit(CustomTransactionEvent event) {if ("BEFORE_COMMIT".equals(event.getEventType())) {System.out.println("Transaction before commit");}}/*** 处理事务提交后事件。** @param event 自定义事务事件*/@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)public void afterCommit(CustomTransactionEvent event) {if ("AFTER_COMMIT".equals(event.getEventType())) {System.out.println("Transaction after commit");}}/*** 处理事务回滚后事件。** @param event 自定义事务事件*/@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)public void afterRollback(CustomTransactionEvent event) {System.out.println("Transaction after rollback");}/*** 处理事务完成后事件。* 注意:@TransactionalEventListener 注解的 phase 参数实际上是用来控制监听器在事务的哪个阶段触发,而不是决定发布的事件类型。* @param event 自定义事务事件*/@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)public void afterCompletion(CustomTransactionEvent event) {if ("AFTER_COMPLETION_COMMITTED".equals(event.getEventType())) {System.out.println("Transaction completed with status: COMMITTED");} else if ("AFTER_COMPLETION_ROLLED_BACK".equals(event.getEventType())) {System.out.println("Transaction completed with status: ROLLED_BACK");}}
}

  这里特别注意:@TransactionalEventListener 注解的 phase 参数实际上是用来控制监听器在事务的哪个阶段触发,而不是决定发布的事件类型。如果这里是eventPublisher.publishEvent(new CustomTransactionEvent("AFTER_COMPLETION_COMMITTED")),那么在发布事务完成后的回调方法中,判断该事件类型的时候会打印Transaction completed with status: COMMITTED

3. 修改TestService服务类

TestService类修改后,在createTest方法中发布自定义事务事件。

package com.example.demo.service;import com.example.demo.event.CustomTransactionEvent;
import com.example.demo.mapper.TestMapper;
import com.example.demo.model.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** Test服务类。*/
@Service
public class TestService {@Autowiredprivate TestMapper testMapper; // 注入TestMapper@Autowiredprivate ApplicationEventPublisher eventPublisher; // 注入事件发布器/*** 创建Test记录。** @param test Test实体*/@Transactionalpublic void createTest(Test test) {System.out.println("createTest is called.");testMapper.insertTest(test); // 插入记录// 发布事务提交前事件eventPublisher.publishEvent(new CustomTransactionEvent("BEFORE_COMMIT"));// 模拟异常以测试事务回滚if ("error".equals(test.getName())) {throw new RuntimeException("Simulated error");}// 发布事务提交后事件eventPublisher.publishEvent(new CustomTransactionEvent("AFTER_COMMIT"));System.out.println("createTest is finished.");}
}

再次运行,看看结果:

在这里插入图片描述
  通过使用 @TransactionalEventListener 注解,我们可以在事务的不同阶段执行相应的逻辑,如记录日志、发送通知、更新缓存等。相比直接实现 TransactionSynchronization 接口,使用注解的方式更加简洁和易于维护。

  但是某些回调方法如 suspend()resume() 不能直接通过注解实现,如果事务传播方式比较复杂且有嵌套,还是建议实现 TransactionSynchronization 接口的方式实现事务监听器。

  在Spring中,通过@TransactionalEventListener注解来监听事务事件需要事件被发布才能被监听到。然而当我们使用TransactionSynchronization接口时,我们不需要显式地发布事件,而是通过直接实现接口的方法来处理事务的各个阶段。因此,如果希望在事务的各个阶段进行监听,并且不想显式发布事件,使用TransactionSynchronization接口是更合适的选择。

5. 时序图:@TransactionalEventListener注解实现事务监听器

在这里插入图片描述

时序图具体解释

  1. 调用业务方法:
  • 客户端调用业务服务的方法,开始一段事务性操作。
  1. 开启事务:
  • 业务服务向事务管理器请求开启一个新的事务。事务管理器负责管理事务的生命周期。
  1. 注册事务事件监听器:
  • 事务管理器在事务开启后注册事务事件监听器,使其能够在事务的不同阶段接收事件通知。
  1. 事务开始:
  • 事务事件监听器记录事务的开始,此时可以进行一些初始化操作。
  1. 执行业务逻辑:
  • 业务服务执行实际的业务逻辑,如数据库操作等。完成后返回结果。
  1. 事务提交前:
  • 在事务提交前,业务服务通过事件发布器发布自定义事务事件(CustomTransactionEvent),表示事务即将提交。
  • 事务事件监听器监听到该事件,并处理该事件(TransactionPhase.BEFORE_COMMIT)。
  1. 提交事务或回滚事务:
  • 事务管理器根据业务逻辑的执行结果决定提交事务或回滚事务。

  • 提交事务:

    • 事务提交后:

      • 提交事务后,业务服务通过事件发布器发布另一个自定义事务事件(CustomTransactionEvent),表示事务已成功提交。
      • 事务事件监听器监听到该事件,并处理该事件(TransactionPhase.AFTER_COMMIT)。
    • 事务完成:

      • 事务提交完成后,再次发布一个事件表示事务已全部完成。
      • 事务事件监听器处理该事件(TransactionPhase.AFTER_COMPLETION)。
  • 回滚事务:

    • 事务回滚后:
      • 如果业务逻辑中出现错误导致事务回滚,业务服务通过事件发布器发布自定义事务事件(CustomTransactionEvent),表示事务已回滚。
      • 事务事件监听器监听到该事件,并处理该事件(TransactionPhase.AFTER_ROLLBACK)。
    • 事务完成:
      • 事务回滚完成后,再次发布一个事件表示事务已全部完成。
      • 事务事件监听器处理该事件(TransactionPhase.AFTER_COMPLETION)。
  1. 业务方法完成:
  • 客户端收到业务方法执行完成的通知。

关键点说明

  • @TransactionalEventListener 注解:用于监听事务事件,并通过 phase 参数指定监听器在事务的哪个阶段触发。这里展示了 TransactionPhase.BEFORE_COMMITTransactionPhase.AFTER_COMMITTransactionPhase.AFTER_ROLLBACKTransactionPhase.AFTER_COMPLETION 四个阶段。

  • 事件发布器:在事务的不同阶段,业务服务通过事件发布器发布自定义事务事件(CustomTransactionEvent),以通知事务事件监听器。

  • 事务事件监听器:监听并处理特定阶段的事务事件,确保在事务的不同阶段执行相应的逻辑。

6. 实际应用场景

  1. 日志记录:

在事务的不同阶段记录日志,帮助开发人员调试和监控系统的运行状况。例如,在事务提交或回滚时记录日志信息,以追踪事务的执行情况。

  1. 缓存更新:

在事务提交成功后更新缓存,以确保缓存中的数据与数据库中的数据一致。这样可以避免在事务尚未提交时缓存数据不一致的问题。

  1. 发送通知:

在事务提交或回滚后发送通知。例如,当订单成功处理时发送确认邮件,当事务回滚时发送警告通知等。

  1. 数据同步:

在分布式系统中,在事务提交后触发数据同步操作,将数据同步到其他服务或系统中,确保数据的一致性和完整性。

  1. 审计和合规:

记录事务的详细信息,以满足审计和合规要求。例如,记录每个事务的执行时间、操作用户、操作内容等信息。

  1. 事件驱动架构:

在事务提交后发布事件,其他组件或服务可以监听这些事件并执行相应的操作。例如,订单服务在订单创建成功后发布订单创建事件,库存服务监听该事件并更新库存。

  1. 事务补偿:

在事务回滚后执行补偿操作。例如,在分布式事务中,如果一个子事务失败,可以通过事务监听器触发补偿逻辑,撤销已经执行的其他子事务。

  1. 安全和审计:

在事务完成后记录安全相关信息,如用户行为日志、安全审计日志等,以确保系统的安全性和合规性。


欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

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

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

相关文章

QQ 小程序已发布,但无法被搜索的解决方案

前言 我的 QQ 小程序在 2024 年 8 月就已经审核通过&#xff0c;上架后却一直无法被搜索到。打开后&#xff0c;再在 QQ 上下拉查看 “最近使用”&#xff0c;发现他出现一下又马上消失。 上线是按正常流程走的&#xff0c;开发、备案、审核&#xff0c;没有任何违规&#xf…

MFC工控项目实例二十九主对话框调用子对话框设定参数值

在主对话框调用子对话框设定参数值&#xff0c;使用theApp变量实现。 子对话框各参数变量 CString m_strTypeName; CString m_strBrand; CString m_strRemark; double m_edit_min; double m_edit_max; double m_edit_time2; double …

C语言 | Leetcode C语言题解之第556题下一个更大元素III

题目&#xff1a; 题解&#xff1a; int nextGreaterElement(int n){int x n, cnt 1;for (; x > 10 && x / 10 % 10 > x % 10; x / 10) {cnt;}x / 10;if (x 0) {return -1;}int targetDigit x % 10;int x2 n, cnt2 0;for (; x2 % 10 < targetDigit; x2…

elementui el-table中给表头 el-table-column 加一个鼠标移入提示说明

前言 在使用el-table 表格中有些表格的表头需要加入一些提示&#xff0c;鼠标移入则出现提示&#xff0c;非常实用&#xff0c;我是通过el-table中的el-tooltip实现的&#xff0c;以下的效果预览 代码实现 <el-table ref"multipleTable" :data"data"…

阿里云通义大模型团队开源Qwen2.5-Coder:AI编程新纪元

&#x1f680; 11月12日&#xff0c;阿里云通义大模型团队宣布开源通义千问代码模型全系列&#xff0c;共6款Qwen2.5-Coder模型。这些模型在同等尺寸下均取得了业界最佳效果&#xff0c;其中32B尺寸的旗舰代码模型在十余项基准评测中均取得开源最佳成绩&#xff0c;成为全球最强…

python 同时控制多部手机

在这个智能时代,我们的手机早已成为生活和工作中不可或缺的工具。无论是管理多个社交媒体账号,还是处理多台设备上的事务,如何更高效地控制多个手机成为了每个人的痛点。 今天带来的这个的软件为你提供了一键控制多部手机的强大功能。无论是办公、娱乐,还是社交,你都能通过…

软件测试:测试用例详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、通用测试用例八要素   1、用例编号&#xff1b;    2、测试项目&#xff1b;   3、测试标题&#xff1b; 4、重要级别&#xff1b;    5、预置…

【操作系统】守护进程

一、守护进程的概念 守护进程是一个在后台运行并且不受任何终端控制的进程 二、自己实现守护进程 1.预备知识 &#xff08;1&#xff09;/dev/null /dev/null是一个特殊的设备文件&#xff0c;往这个文件里写不进去任何数据&#xff0c;也读不出来任何数据 因此&#xff0…

基于微信小程序的乡村研学游平台设计与实现,LW+源码+讲解

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自…

数字后端教程之Innovus report_property和get_property使用方法及应用案例

数字IC后端实现Innovus中使用report_property可以报告出各种各样object的属性&#xff0c;主要有cell&#xff0c;net&#xff0c;PG Net&#xff0c;Pin&#xff0c;时钟clock&#xff0c;时序库lib属性&#xff0c;Design属性&#xff0c;timing path&#xff0c;timin arc等…

Llama架构及代码详解

Llama的框架图如图&#xff1a; 源码中含有大量分布式训练相关的代码&#xff0c;读起来比较晦涩难懂&#xff0c;所以我们对llama自顶向下进行了解析及复现&#xff0c;我们对其划分成三层&#xff0c;分别是顶层、中层、和底层&#xff0c;如下&#xff1a; Llama的整体组成…

sol机器人pump机器人如何实现盈利的?什么是Pump 扫链机器人?

什么是Pump 扫链机器人&#xff0c;它的盈利逻辑优化策略是什么&#xff1f; Pump 扫链机器人&#xff0c;通过智能化、自动化的买卖操作帮助投资者实现快速盈利。在此基础上&#xff0c;我们对该机器人的盈利逻辑进行了深度优化&#xff0c;涵盖了买入策略和止盈策略的各个方面…

三维测量与建模笔记 - 特征提取与匹配 - 4.2 梯度算子、Canny边缘检测、霍夫变换直线检测

从Roberts交叉算子的卷积核可以看出&#xff0c;它实际计算了对角线上元素之间的差值。 prewitt算子实际是对整行或整列、或者对角线两侧的像素进行差分计算。 Sobel算子改进了一下Prewitt算子&#xff0c;增加了权重&#xff0c;中心位置的像素权重为2。 中心权重为4的Laplac…

【2024软考架构案例题】你知道 Es 的几种分词器吗?Standard、Simple、WhiteSpace、Keyword 四种分词器你知道吗?

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

1.7 JS性能优化

从输入url到页面加载完成都做了些什么 输入 URL - 资源定位符 http://www.zhaowa.com - http 协议 域名解析 https://www.zhaowa.com > ip 1. 切HOST&#xff1f; > 浏览器缓存映射、系统、路由、运营商、根服务器 2. 实际的静态文件存放&#xff1f; 大流量 > 多个…

Linux基础1

Linux基础1 Linux基础1学习笔记 ‍ 声明&#xff01; ​​​学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他…

【安全通信】告别信息泄露:搭建你的开源视频聊天系统briefing

文章目录 前言1.关于briefing2.本地部署briefing3.使用briefing4.cpolar内网穿透工具安装5.创建远程连接公网地址6.固定briefing公网地址 前言 在这个信息爆炸的时代&#xff0c;视频聊天几乎成了我们日常沟通的标配。但你是否曾在视频会议中感到不安&#xff0c;担心自己的私…

深度学习——优化算法、激活函数、归一化、正则化

文章目录 &#x1f33a;深度学习面试八股汇总&#x1f33a;优化算法方法梯度下降 (Gradient Descent, GD)动量法 (Momentum)AdaGrad (Adaptive Gradient Algorithm)RMSProp (Root Mean Square Propagation)Adam (Adaptive Moment Estimation)AdamW 优化算法总结 经验和实践建议…

Thread类及常见方法

目录 一、Thread常见构造方法 二、Thread常见属性 三、Thread常见方法 start() 获取当前线程 中断线程 join() 一、Thread常见构造方法 Thread类是JVM用来管理线程的一个类&#xff0c;每个线程都有唯一一个Thread对象与之对应&#xff0c;JVM会将这些对象组织起来&…

优化时钟网络之时钟抖动

Note&#xff1a;文章内容以Xilinx 7系列FPGA进行讲解 1、什么是时钟抖动 时钟抖动就是时钟周期之间出现的偏差。比如一个时钟周期为10ns的时钟&#xff0c;理想情况下&#xff0c;其上升沿会出现在0ns&#xff0c;10ns&#xff0c;20ns时刻&#xff0c;假设某个上升沿出现的时…