详解Java之Spring框架中事务管理的艺术

第1章:引言

大家好,我是小黑,咱们今天聊聊Spring框架中的事务管理。不管是开发小型应用还是大型企业级应用,事务管理都是个不可避免的话题。那么,为什么事务管理这么重要呢?假设在银行系统中转账时,钱从A账户扣了,但没到B账户,这种情况就是事务管理处理不当的后果。显然,我们需要一种机制来确保数据的完整性和一致性。

Spring框架为此提供了一套优雅的事务管理机制,不仅强大,而且相对容易理解和实现。

第2章:事务管理基础

在深入Spring的事务管理之前,咱们先来搞清楚几个基本概念。事务,简单来说,就是一系列操作,要么全部成功,要么全部失败。这就涉及到了ACID原则:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

  • 原子性:事务中的所有操作要么全部完成,要么全部不做。
  • 一致性:事务必须使数据库从一个一致性状态转移到另一个一致性状态。
  • 隔离性:事务的执行不应该被其他事务干扰。
  • 持久性:事务一旦提交,其结果就是永久性的。

在Java世界里,事务管理最初是通过JDBC来实现的。但这种方式很快就显得力不从心,因为它需要程序员手动管理很多细节,容易出错。而Spring提供了一种声明式的事务管理方法,极大地简化了事务的处理方式。那么,Spring是怎么做到的呢?让小黑来给大家展示一下。

import org.springframework.transaction.annotation.Transactional;public class TransferService {@Transactionalpublic void transferMoney(String fromAccountId, String toAccountId, Double amount) {// 这里是一些转账的业务逻辑// 比如,从一个账户扣款,向另一个账户存款}
}

在这段代码里,@Transactional 注解是Spring事务管理的核心。只要在方法上加上这个注解,Spring就会自动处理这个方法的事务。如果方法成功执行完毕,事务就会被提交;如果出现异常,事务就会回滚。这就是声明式事务管理的魅力所在:简单、直观、易于理解和使用。

相比之下,传统的事务管理方式则需要咱们手动控制事务的每个阶段,比如开始事务、提交事务或回滚事务。这不仅代码量大,而且容易出错。小黑来给大家看一个传统的JDBC事务管理示例:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class TraditionalTransaction {public void transferMoney(String fromAccountId, String toAccountId, Double amount) {Connection conn = null;try {conn = getConnection(); // 获取数据库连接conn.setAutoCommit(false); // 开始事务// 执行一系列数据库操作// ...conn.commit(); // 提交事务} catch (SQLException e) {if (conn != null) {try {conn.rollback(); // 出错时回滚事务} catch (SQLException ex) {ex.printStackTrace();}}e.printStackTrace();} finally {if (conn != null) {try {conn.close(); // 关闭连接} catch (SQLException e) {e.printStackTrace();}}}}private Connection getConnection() {// 这里是获取数据库连接的代码return null;}
}

从上面的例子可以看出,传统的方式让事务管理变得繁琐而且易出错。而Spring的声明式事务管理则大大简化了这一过程。

第3章:Spring框架中的事务抽象

事务抽象的关键组件

Spring事务抽象的核心是PlatformTransactionManager接口。这个接口为不同的事务管理策略提供了一个标准化的方法。不同的数据库和持久化框架(比如JDBC、Hibernate)都有对应的实现。

来看看PlatformTransactionManager的一个基本示例:

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;public class TransactionManagerExample {private PlatformTransactionManager transactionManager;public void performTransaction() {TransactionDefinition definition = new DefaultTransactionDefinition();// 开始事务TransactionStatus status = transactionManager.getTransaction(definition);try {// 执行业务逻辑// ...transactionManager.commit(status); // 事务提交} catch (Exception e) {transactionManager.rollback(status); // 事务回滚}}
}

在这个例子中,小黑使用PlatformTransactionManager来明确开始和结束一个事务。这种方式虽然比传统的JDBC事务管理更为抽象,但仍然需要手动控制事务的边界。

事务定义和传播

在Spring中,事务是通过TransactionDefinition接口定义的。这个接口包含了各种与事务相关的属性,如隔离级别、超时时间、只读状态等。这些属性允许咱们根据具体需求定制事务的行为。

举个例子,如果小黑想要创建一个新的、独立于当前事务的事务,可以这样做:

import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

在这段代码中,PROPAGATION_REQUIRES_NEW 表示如果当前存在事务,则挂起当前事务,并创建一个全新的事务。这种灵活性是Spring事务管理非常强大的一个方面。

事务状态和回滚

除了定义事务,Spring还提供了TransactionStatus接口来跟踪事务的当前状态。这个接口让咱们可以在运行时检查事务是否已经完成,是否有回滚等。

在事务过程中,如果发生了异常,Spring允许咱们明确指定哪些异常应该触发事务回滚。这是通过@Transactional 注解的rollbackFor 属性实现的:

import org.springframework.transaction.annotation.Transactional;@Transactional(rollbackFor = Exception.class)
public void someTransactionalMethod() {// ...
}

在这个例子中,任何Exception类型的异常都会触发事务回滚。这种灵活的异常处理机制使得事务管理更加健壮和可靠。

第4章:声明式事务管理

现在小黑带大家深入了解Spring的声明式事务管理。在Spring中,声明式事务管理是通过@Transactional注解来实现的。这种方法的好处是极大地简化了代码,让事务管理变得更加直观和容易维护。

使用@Transactional注解

@Transactional注解可以应用于类或者方法上。当应用于类时,该类中的所有公共方法都会被视为事务方法。而当应用于方法时,只有标注了该注解的方法才会被视为事务方法。

来看一个简单的例子:

import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;@Service
public class AccountService {@Transactionalpublic void transferFunds(String fromAccountId, String toAccountId, Double amount) {// 这里是转账的业务逻辑// 包括从一个账户扣钱和向另一个账户加钱// 如果在这个过程中发生任何异常,事务将自动回滚}
}

在这个例子中,transferFunds 方法上的@Transactional注解告诉Spring,这个方法需要在事务环境中运行。如果在执行过程中发生异常,Spring将自动回滚事务。

事务的传播行为

事务的传播行为定义了事务方法之间相互调用时的行为。Spring提供了多种传播行为选项,例如PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEW等。这些选项可以根据业务需求进行选择。

例如,小黑想要创建一个新的事务,而不管当前是否存在事务,可以这样设置:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void someMethod() {// ...
}
只读事务

如果事务仅涉及到数据读取,没有数据的修改,小黑可以将事务标记为只读。这可以优化事务的执行,特别是在使用某些类型的事务管理器(如Hibernate事务管理器)时。

例如:

@Transactional(readOnly = true)
public List<Account> findAllAccounts() {// ...
}
事务的隔离级别

事务的隔离级别决定了一个事务可能受其他并发事务影响的程度。Spring提供了与J

DBC相同的隔离级别,例如ISOLATION_READ_COMMITTEDISOLATION_SERIALIZABLE等。小黑可以根据具体的数据一致性和并发要求选择合适的隔离级别。

比如,如果小黑希望在事务中防止脏读,可以设置隔离级别为 READ_COMMITTED

@Transactional(isolation = Isolation.READ_COMMITTED)
public void someSensitiveOperation() {// 这里的操作会避免脏读的发生
}
异常回滚策略

在声明式事务管理中,Spring默认只在运行时异常和错误发生时回滚事务。但是,小黑可以自定义回滚规则,指定特定的异常类型来触发事务回滚。

例如,如果小黑想要在特定的检查型异常发生时也回滚事务,可以这样设置:

@Transactional(rollbackFor = {CustomCheckedException.class})
public void someOperation() throws CustomCheckedException {// ...
}

通过这些设置,咱们可以非常灵活地控制事务的行为,以满足不同的业务需求。声明式事务管理不仅使得事务的使用变得简单,而且提高了代码的清晰度和可维护性。

第5章:编程式事务管理

何时使用编程式事务管理

编程式事务管理是在代码中显式地控制事务的开始、提交和回滚。这种方式在需要对事务进行细粒度控制的场景下非常有用。比如,当事务操作需要根据运行时的某些条件动态决定,或者在一个大的事务中需要处理多个独立的小事务时。

使用TransactionTemplate

Spring为编程式事务管理提供了一个方便的类:TransactionTemplate。这个类简化了编程式事务管理,让咱们能够更加方便地实现事务逻辑。

来看看TransactionTemplate的基本用法:

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;public class ProgrammaticallyTransaction {private final TransactionTemplate transactionTemplate;public ProgrammaticallyTransaction(PlatformTransactionManager transactionManager) {this.transactionTemplate = new TransactionTemplate(transactionManager);}public Object someBusinessLogic() {return transactionTemplate.execute(new TransactionCallback<Object>() {@Overridepublic Object doInTransaction(TransactionStatus status) {// 这里写入事务的业务逻辑// 可以根据需要调用status.setRollbackOnly()来回滚事务return null;// 返回值可以是业务逻辑的结果}});}
}

在这个例子中,咱们使用TransactionTemplate来定义一个事务块。execute方法接受一个TransactionCallback,其中包含了要在事务中执行的业务逻辑。如果在执行过程中没有异常抛出,事务将自动提交;如果有异常抛出或显式调用status.setRollbackOnly(),事务将回滚。

使用PlatformTransactionManager

对于想要更深层次控制事务的小黑,可以直接使用PlatformTransactionManager。这种方法

提供了对事务操作最完全的控制,但也意味着需要更多的代码和复杂性。

让我们来看一个使用PlatformTransactionManager的例子:

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;public class ManualTransaction {private final PlatformTransactionManager transactionManager;public ManualTransaction(PlatformTransactionManager transactionManager) {this.transactionManager = transactionManager;}public void executeBusinessLogic() {TransactionDefinition definition = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(definition);try {// 这里进行具体的业务操作// ...transactionManager.commit(status); // 业务成功,提交事务} catch (Exception e) {transactionManager.rollback(status); // 出现异常,回滚事务throw e;}}
}

在这段代码中,咱们首先创建了一个TransactionDefinition对象来定义事务的属性,然后通过transactionManager.getTransaction(definition)开始一个新的事务,并获取一个TransactionStatus对象。这个对象可以用来在事务执行过程中检查事务的状态,以及在需要时回滚事务。如果业务逻辑顺利完成,就调用transactionManager.commit(status)来提交事务;如果捕获到异常,则调用transactionManager.rollback(status)来回滚事务。

编程式事务管理虽然提供了更多的灵活性和控制力,但也带来了更多的复杂性。咱们在选择使用哪种事务管理策略时,需要考虑到业务逻辑的复杂性和对事务控制的需求。

声明式事务管理对于大多数情况下已经足够好用,但当需要特定的事务控制逻辑时,编程式事务管理就显得尤为重要了。

编程式事务管理让咱们能够精确控制事务的每个细节,这在处理复杂的业务逻辑或者需要根据不同情况灵活处理事务时非常有用。例如,在一个复杂的数据处理过程中,可能只有部分步骤需要事务控制,或者需要根据某些条件动态决定是否回滚事务。在这些情况下,编程式事务管理提供了必要的灵活性和精确控制。

第6章:Spring事务管理的高级特性

事务的传播行为

在Spring中,事务的传播行为定义了一个事务方法是如何关联到现有事务的。这对于理解和设计复杂的事务逻辑非常关键。

  • PROPAGATION_REQUIRED:如果当前有事务,就加入该事务;如果没有,就新建一个事务。
  • PROPAGATION_REQUIRES_NEW:总是创建一个新的事务,如果有现有事务,将其挂起。
  • PROPAGATION_SUPPORTS:如果当前有事务,就加入事务,没有则非事务方式执行。
  • ……更多行为如PROPAGATION_MANDATORYPROPAGATION_NEVER等。

来看个例子:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void someMethod() {// 这个方法总是在新的事务中运行
}
事务的隔离级别

事务的隔离级别决定了一个事务对于其他并发事务的可见性。不同的隔离级别可以防止诸如脏读、不可重复读、幻读等问题。

  • ISOLATION_READ_UNCOMMITTED:允许读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读。
  • ISOLATION_READ_COMMITTED:允许在一个事务中读取另一个已经提交的事务所做的更改。
  • ISOLATION_REPEATABLE_READ:确保如果在事务中一次读取了数据,则可以多次重复读取同样的数据。
  • ISOLATION_SERIALIZABLE:完全遵守ACID的原则,确保不发生脏读、不可重复读和幻读。

例如:

@Transactional(isolation = Isolation.SERIALIZABLE)
public void performHighlySensitiveOperation() {// 这里的操作将会在最严格的隔离级别下执行
}
只读事务和超时设置
  • 只读事务:如果事务只是读取

数据而不做任何更新,小黑可以将事务标记为只读。这样做可以帮助数据库优化事务,提高性能。

@Transactional(readOnly = true)
public List<User> getUsers() {// 这个事务只读取数据,不做修改
}
  • 超时设置:在Spring中,可以为事务指定一个超时时间。如果事务超出了这个时间范围,它会被自动回滚。这对于避免长时间占用资源非常有用。
@Transactional(timeout = 10) //10秒超时
public void processLargeData() {// 这个事务处理大量数据,但如果超过10秒还没完成,就会自动回滚
}

通过设置只读事务和超时时间,咱们可以进一步优化事务的性能和稳定性,特别是在处理大量数据或者复杂查询时。

事务同步和异常处理

在Spring事务管理中,事务同步是指事务的状态与正在执行的业务逻辑之间的协调。Spring通过TransactionSynchronizationManager来管理事务同步,确保资源(如数据库连接)在事务开始时打开,在事务结束时正确关闭。

异常处理也是事务管理中的重要部分。默认情况下,Spring只在运行时异常发生时回滚事务。但咱们可以通过@Transactional注解的rollbackFor属性来自定义哪些异常应该触发回滚。

例如:

@Transactional(rollbackFor = {CustomException.class})
public void serviceMethod() {// 这个方法在抛出CustomException时会触发事务回滚
}

通过理解和运用这些高级特性,咱们可以在Spring中实现复杂且健壮的事务管理策略。这些功能使得Spring事务管理非常强大,满足了各种复杂业务场景的需求。

第7章:事务同步和异常处理

事务同步

在Spring中,事务同步主要是指在事务过程中保持数据源、缓存、消息等资源的一致状态。这是通过TransactionSynchronizationManager来实现的,它是Spring事务管理的核心组件之一。

TransactionSynchronizationManager可以注册事务同步回调,以便在事务的不同阶段执行特定的操作。例如,可以在事务提交或回滚时清除缓存,或者更新某些与事务状态相关的数据。

来看个示例:

import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;public void registerSynchronization() {TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {// 事务提交后执行的操作// 例如,清除某些缓存}@Overridepublic void afterCompletion(int status) {// 事务完成后执行的操作(无论是提交还是回滚)// 例如,发送通知或更新状态}});
}
异常处理

在Spring的事务管理中,正确处理异常是保证事务正确回滚的关键。Spring默认在遇到运行时异常和错误时回滚事务。对于检查型异常,默认情况下不会触发回滚。

咱们可以通过在@Transactional注解中指定rollbackFornoRollbackFor属性来定制哪些异常应该触发事务回滚,哪些不应该。

例如,小黑想在特定的检查型异常发生时回滚事务:

import org.springframework.transaction.annotation.Transactional;@Transactional(rollbackFor = {MyCheckedException.class})
public void myTransactionalMethod() throws MyCheckedException {// 这里的代码在抛出MyCheckedException异常时会触发事务回滚
}

反之,如果小黑想要在特定的运行时异常发生时不回滚事务,可以这样设置:

@Transactional(noRollbackFor = {MyRuntimeException.class})
public void anotherTransactionalMethod() {// 这里的代码在抛出MyRuntimeException时不会触发事务回滚
}

正确的异常处理策略对于维持数据库的一致性和避免不必要的数据损失至关重要。咱们在设计事务管理逻辑时,需要仔细考虑哪些操作可能会抛出异常,以及这些异常应如何影响事务的行为。

事务同步不仅帮助管理事务内部的资源,还能够确保事务的外部效应(如缓存更新、消息发送等)与事务状态保持一致。而灵活而强大的异常处理机制则允许咱们精确控制事务的回滚行为,从而更好地应对复杂的业务场景。掌握了这些知识,咱们就能更加自信地管理和优化自己的Spring应用了。

第8章:最佳实践和常见问题

最佳实践
  1. 明智地选择事务边界:确保事务不会太大或太小。过大的事务可能会锁定太多资源,影响性能;过小的事务则可能无法有效保护数据的完整性。

  2. 合理使用声明式和编程式事务管理:尽管声明式事务管理更简洁,但在需要更细致控制的场景下,编程式事务管理可能更合适。

  3. 避免事务中的远程调用:在事务中进行远程调用(如HTTP请求、远程方法调用)会增加事务持续时间,增加数据库锁定时间,影响系统性能。

  4. 不要在事务中处理太多的业务逻辑:尽量保持事务简洁,聚焦于数据访问操作,以减少事务执行时间。

  5. 仔细选择事务的隔离级别:不同的隔离级别有不同的性能影响。选择恰当的隔离级别可以避免不必要的性能开销。

常见问题及解决方案
  1. 问题:事务不回滚
    解决方案:检查是否正确使用了@Transactional注解,以及是否在适当的异常上触发了回滚。

  2. 问题:事务管理器没有正确配置

    解决方案:确保Spring配置中正确声明了事务管理器,并且所有事务相关的操作都在其管理范围内。

  3. 问题:不恰当的事务传播行为导致的问题
    解决方案:理解不同事务传播行为的含义,根据具体的业务场景选择合适的传播行为。

  4. 问题:脏读、不可重复读和幻读
    解决方案:通过设置合适的事务隔离级别来避免这些问题。例如,ISOLATION_REPEATABLE_READ可以防止不可重复读,ISOLATION_SERIALIZABLE可以防止幻读。

  5. 问题:长事务影响系统性能
    解决方案:重新审视业务逻辑,将长事务拆分成多个短事务,或将非关键操作移出事务。

示例:选择正确的事务传播行为

在使用Spring事务时,正确选择事务传播行为是非常关键的。例如,假设有一个服务类需要在已有事务中执行,可以使用PROPAGATION_REQUIRED

import org.springframework.transaction.annotation.Transactional;@Transactional(propagation = Propagation.REQUIRED)
public class MyService {public void performService() {// 业务逻辑}
}

如果这个方法需要在自己的独立事务中执行,而不管外部是否存在事务,可以使用PROPAGATION_REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
public class MyService {public void performIndependentService() {// 独立的业务逻辑}
}

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

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

相关文章

06-微服务OpenFeigh和Sentinel持久化

一、OpenFeign基础应用 1.1 概念 OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign&#xff0c;可以做到使用HTTP请求访问远程服务&#xff0c;就像调用本地方法一样的&#xff0c;开发者完全感知不到这是在调用远程方法&#xff0c;更感知不到在访…

VITS(Conditional Variational Autoencoder with Adversarial Learning)论文解读及实现(一)

此篇为VITS论文解读第一部份 论文地址Conditional Variational Autoencoder with Adversarial Learning for End-to-End Text-to-Speech模型使用了VAE,GAN,FLOW以及transorflomer(文本处理有用到)&#xff0c;即除了未diffusion模型&#xff0c;将生成式模型都融入进来了&#…

064:vue中一维数组的全选、全不选、反选(图文示例)

第061个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

DHCP中继【新华三】

理论【DHCP服务器可以对其直连的网段中的pc&#xff0c;分配其IP地址等服务&#xff0c;但是&#xff0c;对于跨网段进行分配IP地址&#xff0c;需要中间有DHCP中继进行传达&#xff0c;由DHCP中继指定DHCP服务器的位置&#xff0c;可以很好的对其跨网段分配IP地址起到指引的作…

限时福利,Adobe InCopy2024下载安装指南

Adobe InCopy 下载链接 https://pan.baidu.com/s/16j5MiXqfGw6puQbgyQnJSQ?pwd0531 #2024版本 1.鼠标右击【InCopy2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 InCopy2024(64bit)】。 2.打开解压后的文件夹&#xff0c;鼠…

Kubernetes 1.24正式发布,2022年首个大版本更新

介绍 早在 2020 年 12 月&#xff0c;Kubernetes 就宣布弃用 Dockershim。在 Kubernetes 中&#xff0c;dockershim 是一个软件 shim&#xff0c;它允许您将 Docker 引擎用作 Kubernetes 中的容器运行时。 这个版本包含 46 个增强功能&#xff1a;14 个增强功能已经升级到稳定…

【软件测试】学习笔记-设计GUI自动化测试策略

这篇文章从“实战”这个角度展开&#xff0c;探讨实际的大型全球化电商网站的GUI自动化测试如何开展。这场实战&#xff0c;从以下两个方面展开&#xff1a; 测试策略如何设计&#xff1f;这一点&#xff0c;我会根据亲身经历的实际项目&#xff0c;和你探讨GUI测试的分层测试…

Leetcode26——引出c++ vector中erase()的内部原理

erase是对数组中某个元素进行删除的操作&#xff0c;实际的时间复杂度为O(n) 预备知识 数组在内存中是连续存储的&#xff0c;删除某个位置的时候不能直接删除&#xff0c;只能用后序的元素覆盖 以nums数组为例&#xff0c;target为需要删除的目标数据 方法&#xff1a; ①…

codeforces (C++ Satisfying Constraints)

题目&#xff1a; 翻译&#xff1a; 思路&#xff1a; 1、找到最大的下限min 2、找到最小的上限max 3、则max-min1满足1、2约束条件的个数 4、max-min1减去约束条件3的个数&#xff0c;即为最终答案 5、如果min大于max&#xff0c;则结果为0&#xff0c;不存在满足约束条件的数…

【天龙怀旧服】攻略day7

关键字&#xff1a; 新星1.49、金针渡劫、10灵 1】新星&#xff08;苍山破煞&#xff09; 周三周六限定副本&#xff0c;19.00-24.00 通常刷1.49w&#xff0c;刷149点元佑碎金 boss选择通常为狂鬼难度&#xff0c;八风不动即放大不选&#xff0c;第二排第一个也不选&#xf…

RSIC-V“一芯”学习笔记(二)——Linux入门教程

文章目录 一、前言二、Busybox套件三、重要的追踪工具——strace四、Shell五、正则表达式六、重定向&#xff08;多次输入测试时&#xff09;七、一些组合命令八、自动化脚本九、学会查阅十、亲&#xff08;yuan&#xff09;近(li) bai du十一、不要逃避困难十二、重视小问题 一…

Grounding DINO:开放集目标检测,将基于Transformer的检测器DINO与真值预训练相结合

文章目录 背景知识补充CLIP (Contrastive Language-Image Pre-training)&#xff1a;打破文字和图像之间的壁垒DINO(Data-INterpolating Neural Network)&#xff1a;视觉 Transformer 的自监督学习Stable Diffusion&#xff1a;从文本描述中生成详细的图像Open-set Detector开…

【教3妹学编程-算法题】最大频率元素计数

2哥 : 3妹&#xff0c;最近有个电视剧《繁花》非常火&#x1f525;&#xff0c;你听说了吗&#xff1f; 3妹&#xff1a;没有&#xff0c;最近一直在忙着找工作&#xff0c;哪有时间看电视啊 2哥 : 啊&#xff1f;大周末还不休息一下啊&#xff0c;这么辛苦。 3妹&#xff1a;当…

Video接口介绍

屏库 https://m.panelook.cn/index_cn.php Open LDI, open lvds display interface OpenLDI and LVDS是兼容的&#xff0c; 是一种电平 https://www.ti2k.com/178597.html MIPI DSI/Camera crosLink FPD-LINK(Flat panel display link)是National(TI) LVDS技术&#xff0c; …

如何在线生成App:将网页封装成APP

在数字化时代&#xff0c;App已成为我们日常生活中不可或缺的一部分。然而&#xff0c;对于众多企业和个人开发者来说&#xff0c;开发一个原生App既耗时又耗资&#xff0c;尤其当他们已经拥有一个功能完备的网站时。幸运的是&#xff0c;现在有一种方法可以将现有的网页封装成…

k8s node节点加入集群,token过期

1、master01节点执行 kubeadm token create --print-join-command 2、执行命令 kubeadm join 192.168.0.236:16443 --token qucd8q.hsfq4a1afluzaky3 --discovery-token-ca-cert-hash sha256:92175a356db070deb2ddd3823e288e3005a4baeec9b68580dcc11ce4d3767195 3、查看node02…

【含完整代码】Java定时任务之xxl-job[超详细]

前言 个人博客&#xff1a;www.wdcdbd.com 在Java中使用定时任务是一件很常见的事情&#xff0c;比如使用定时任务在什么时间&#xff0c;什么时候&#xff0c;去发布一些信息&#xff0c;或者去查询一些日志等相关的代码。这时&#xff0c;我们就要开发定时任务这中功能来实现…

PyGWalker,一款超级强大的数据分析和数据可视化的工具库

PyGWalker可以有效简化Jupyter笔记本的数据分析和数据可视化工作流程&#xff0c;方法是将panda数据帧转换为Tableau风格的用户界面进行可视化探索。 PyGWalker被命名为“Graphic Walker的Python绑定”的缩写。它集成了Jupyter笔记本&#xff08;或其他基于Jupyter的笔记本&am…

Linux之静态库和动态库

目录 一、前言 二、对于库的理解 三、静态库 四、动态库 五、动静态库的加载 一、前言 在之前&#xff0c;我们讲了静态库和动态库&#xff0c;详情请跳转&#xff1a;静态库和动态库 下面我们将从工程师的角度&#xff0c;去了解静态库和动态库的形成过程&#xff0c;以…

【Linux操作】国产Linux服务管理操作

【Linux操作】国产Linux服务管理操作 前言SAMBA配置服务器端1. 安装相关包2. 配置/etc/samba/smb.conf&#xff0c;在此文件末尾添加如下内容&#xff0c;并保存退出。3. 创建/home/share并更改权限4. 启动samba服务 客户端• Windows客户端• 麒麟客户端 Telnet1、telnet语法2…