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

news2024/10/7 18:20:19

第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 {

    @Transactional
    public 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 {

    @Transactional
    public 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>() {
            @Override
            public 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() {
        @Override
        public void afterCommit() {
            // 事务提交后执行的操作
            // 例如,清除某些缓存
        }

        @Override
        public 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.coloradmin.cn/o/1385172.html

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

相关文章

Java实现海南旅游景点推荐系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

远程开发之vscode端口转发

远程开发之vscode端口转发 涉及的软件forwarded port 通过端口转发&#xff0c;实现在本地电脑上访问远程服务器上的内网的服务。 涉及的软件 vscode、ssh forwarded port 在ports界面中的port字段&#xff0c;填需要转发的IP:PORT&#xff0c;即可转发远程服务器中的内网端…

SSH镜像、systemctl镜像、nginx镜像、tomcat镜像

目录 一、SSH镜像 二、systemctl镜像 三、nginx镜像 四、tomcat镜像 五、mysql镜像 一、SSH镜像 1、开启ip转发功能 vim /etc/sysctl.conf net.ipv4.ip_forward 1sysctl -psystemctl restart docker 2、 cd /opt/sshd/vim Dockerfile 3、生成镜像 4、启动容器并修改ro…

AirServer2024官方最新版免费下载

AirServer官方版是一款使用方便的投屏软件&#xff0c;在教室&#xff0c;会议室以及游戏中极为方便。AirServer官方版支持IOS、Android、Windows、mac、Chromebook等多种设备&#xff0c;使用AirServer不需要其他的设备即可完成投屏操作&#xff0c;相比其他投屏软件&#xff…

星图地球——Landsat5_C2_TOA_T1数据集

简介 Landsat 5是美国陆地卫星系列&#xff08;Landsat&#xff09;的第五颗卫星&#xff0c;于1984年3月1日发射&#xff0c;2011年11月停止工作。16天可覆盖全球范围一次。Landsat5_C2_TOA数据集是由Collection2 level1数据通过MTL文件计算得到的TOA反射率产品。数据集的空间…

Spring Boot 中实现文件上传、下载、删除功能

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

VUE好看的个人简历模板

文章目录 1.设计来源1.1 首页界面1.2 关于我界面1.3 我的资历界面1.4 项目经验界面1.5 我的技能界面1.6 联系我界面 2.效果和源码2.1 动态效果2.2 源码目录结构 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/…

【python】12.字符串和正则表达式

使用正则表达式 正则表达式相关知识 在编写处理字符串的程序或网页时&#xff0c;经常会有查找符合某些复杂规则的字符串的需要&#xff0c;正则表达式就是用于描述这些规则的工具&#xff0c;换句话说正则表达式是一种工具&#xff0c;它定义了字符串的匹配模式&#xff08;…

网站万词霸屏推广系统源码:实现关键词推广,轻松提高关键词排名,带完整的安装部署教程

现如今&#xff0c;互联网的快速发展&#xff0c;网站推广成为企业网络营销的重要手段。而关键词排名作为网站推广的关键因素&#xff0c;一直备受关注。罗峰给大家分享一款网站万词霸屏推广系统源码&#xff0c;该系统可实现关键词推广&#xff0c;有效提高关键词排名&#xf…

Github 2024-01-15开源项目周报Top14

根据Github Trendings的统计&#xff0c;本周(2024-01-15统计)共有14个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目6TypeScript项目3Jupyter Notebook项目3Java项目2Kotlin项目1C#项目1C项目1 Microsoft PowerToys:…

实现STM32烧写程序-(2)Flash Loader 发送指令解析

简介 实现STM32烧写程序-(1)获取Bootloader版本信息&#xff0c; 看了数据手册之后可以了解到指令的发送, 但实现之前可以使用现成的工具进行测试和查看他的收发情况; Usart Bootloader 指令列表 Usart Bootloader 指令列表 应答ACK | NACK ACK(0x79) 表示 正常答复, NACK(0x…

mybatis中的驼峰转换

一、有啥用 开发时常用对象来存储从数据库中的记录&#xff0c;开启驼峰转化即可实现数据库字段(通常使用_下划线连接)与对象属性的对应&#xff0c;如数据库中的first_name字段会转化为firstName与对象中的firstName属性对应。 二、配置 三、相关报错 数据库字段与对象属性…

我为什么要写RocketMQ消息中间件实战派上下册这本书?

我与RocketMQ结识于2018年&#xff0c;那个时候RocketMQ还不是Apache的顶级项目&#xff0c;并且我还在自己的公司做过RocketMQ的技术分享&#xff0c;并且它的布道和推广&#xff0c;还是在之前的首席架构师的带领下去做的&#xff0c;并且之前有一个技术神经质的人&#xff0…

广告投放场景中ABtest分析的评价、优化和决策建议

写在开头 在当今数字化的商业环境中&#xff0c;广告投放是企业获取客户和推动销售的重要手段。然而&#xff0c;随着市场竞争的加剧&#xff0c;制定有效的广告策略变得愈发复杂。在这个背景下&#xff0c;AB测试成为了广告主们不可或缺的工具之一。本文将深入探讨广告投放中…

swing快速入门(四十四)拖动、编辑JTree结点

注释很详细&#xff0c;直接上代码 新增内容&#xff08;源码细节知识点巨多&#xff0c;建议细看&#xff09; 1.设置JTree可编辑 2.使用JTree关联的数据模型实现节点的增删改 3.鼠标拖动节点事件设计及处理方法 4.手动刷新视图与自动刷新的方法区别 5.自定位节点视图方法 源码…

zepplin记录1

zepplin记录1 文章目录 zepplin记录1前言一、配置python环境二、测试可用性1.配置interpreter2.测试代码 总结 前言 Apache Zeppelin是一个开源的数据分析和可视化的交互式笔记本&#xff0c;类似于Jupyter Notebook。它支持多种编程语言&#xff08;如Scala、Python、R、SQL等…

多线程——阻塞队列

什么是阻塞队列 相比于一般的队列&#xff0c;有两个特点 1.线程安全 2.带有阻塞功能 1&#xff09;队伍为空时&#xff0c;出队列就会出现阻塞&#xff0c;阻塞到其他线程入队列为止 2&#xff09;队伍为满时&#xff0c;入队列就会出现阻塞&#xff0c;阻塞到其他线程出队列…

pandas查看数据常用方法(以excel为例)

目录 1.查看指定行数的数据head() 2. 查看数据表头columns 3.查看索引index 4.指定索引列index_col 5.按照索引排序 6.按照数据列排序sort_values() 7.查看每列数据类型dtypes 8.查看指定行列数据loc 9.查看数据是否为空isnull() 1.查看指定行数的数据head() &#xff…

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

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

CAN/CANFD数据记录仪汽车电子售后神器

CAN数据记录仪是一种用于采集和存储CAN总线数据的工具&#xff0c;广泛应用于汽车、轨道车辆、工业控制等大数据量且不易排查故障的系统中。它可以实时存储总线上的数据&#xff0c;方便后续的研究和分析。解决工程师售后难点。 在选择CAN数据记录仪时&#xff0c;需要根据实…