Neo4j的事务管理和锁行为

后端领域 Spring Data Neo4j 的事务管理策略 Spring Data Neo4j 是 Spring 生态系统中用于与 Neo4j 图数据库进行交互的强大工具。在后端开发中,事务管理是确保数据一致性和完整性的关键环节。本文的目的在于深入探讨 Spring Data Neo4j 的事务管理策略,详细介绍其原理、实现方式以及实际应用中的注意事项。范围涵盖从基础概念到高级应用,包括核心算法、数学模型、项目实战等方面,旨在为开发者提供全面且深入的指导。本文首先介绍背景知识,包括目的、预期读者和文档结构。接着阐述核心概念与联系,展示其原理和架构的示意图及流程图。 阅读详情

原文链接:https://neo4j.com/docs/java-reference/current/transaction-management/

1. 概述

为了充分维护数据完整性并确保良好的事务行为,Neo4j 支持 ACID 的四大属性:

  • 原子性,如果事务的任何部分失败,数据库状态保持不变。
  • 一致性,任何事务都会使数据库处于一致状态。
  • 隔离性,在一个事务期间,修改过的数据不能被其他操作访问。
  • 持久性,DBMS 始终可以恢复已提交事务的结果。

具体来说:

  • 访问图、索引或模式的所有数据库操作都必须在事务中执行。
  • 默认隔离级别是读提交(read-commited)隔离级别。
  • 通过遍历检索得到的数据结果不被保护,其他事务可以修改。
  • 可能会发生不可重复读(例如,仅获取写锁并保持到事务结束)。
  • 可以手动获取节点和关系上的写锁,以实现更高级别的隔离 --序列化隔离级别(serialization isolation )。
  • 在节点和关系级别获取锁。
  • 死锁检测内置于核心事务管理中。


1. 执行周期

有些数据库操作必须在事务中执行以确保 ACID 属性。具体来说,访问图、索引或模式的操作就属于这类操作。事务是单线程的、受限的和独立的。多个事务可以在单个线程中启动,并且它们彼此保持独立。

处理事务的交互周期如下所示:

  • 开始事务。
  • 执行数据库操作。
  • 提交或回滚事务。

完成每个事务非常重要。事务在完成之前不会释放它所获得的锁或内存。

Neo4j 中事务的惯用用法是使用 try-with-resources 语句并将事务声明为资源之一,然后启动事务并尝试执行图操作。 try 块中的最后一个操作应该提交或回滚事务,具体取决于业务逻辑。在这种情况下,try-with-resources 被用作防止异常的保护措施和额外的安全机制,以确保无论语句块内发生什么事情都可以关闭事务。所有未提交的事务将在语句结束时作为资源清理的一部分回滚。如果事务已明确提交或回滚,则不需要资源清理,事务关闭将是一个空操作。

在事务中执行的所有修改都保存在内存中,这意味着需要将非常大的更新拆分为多个事务以避免内存不足。

2. 隔离级别

Neo4j 中的事务使用读提交隔离级别,这意味着它们会在数据提交后立即看到数据,但不会看到其他尚未提交的事务中的数据。这种类型的隔离比序列化弱,但提供了显着的性能优势,同时足以满足绝大多数情况。

此外,Neo4j Java API 支持显式锁定节点和关系。使用锁可以通过显式获取和释放锁来模拟更高级别隔离的效果。例如,如果在公共节点或关系上获取写锁,则所有事务都将在该锁上进行序列化 – 相当于序列化隔离级别的效果。

2.1. Cypher 中丢失的更新

在 Cypher 中,在某些情况下可以获取写锁来模拟改进的隔离级别。想象一下当多个并发 Cypher 查询在增加同一属性值的情况。由于已提交读隔离级别的限制,增量可能不会产生确定性的最终值。如果存在“直接依赖“”,Cypher 会在读取前自动获取写锁。“直接依赖”是指在 SET 语句的右侧表达式中有对依赖的属性的读取操作,或者一个Map中有对键-值对的中值的读取。

例如以下查询,如果由一百个并发客户端运行,则很可能不会将属性 n.prop 增加到 100,除非在读取属性值之前获取了写锁。这是因为所有查询都会在它们自己的事务中读取 n.prop 的值,并且不会从任何其他尚未提交的事务中看到已经增加值。在最坏的情况下,如果所有线程在任何其他线程提交其事务之前完成读取,则最终值将可能就是1(假设n.prop的初始值是0)。

示例 1. Cypher 可以获取写锁

下面的例子需要一个写锁,Cypher 会自动获取一个:

MATCH (n:X {id: 42})
SET n.prop = n.prop + 1

示例 2. Cypher 可以获得写锁

这个例子也需要一个写锁,Cypher 会自动获取一个:

MATCH (n)
SET n += { prop: n.prop + 1 }

由于确定此类依赖项存在相当的复杂,Cypher 不涵盖下面的示例情况。

示例 3. 复杂Cypher

变量取决于读取语句之前若干行的某个属性的结果

MATCH (n)
WITH n.prop as p
// ... operations depending on p, producing k
SET n.prop = k + 1

示例 4. 复杂Cypher

在同一查询中存在读取和写入属性之间的循环依赖:

MATCH (n)
SET n += { propA: n.propB + 1, propB: n.propA + 1 }

为了在更复杂的情况下也保证执行的确定性,有必要很清楚的获取有关节点的写锁。 在 Cypher 中,对此没有明确的支持,但可以通过写入临时属性来解决此限制。

示例 5. 明确获取写锁

此示例通过在读取请求值之前写入虚拟属性来获取节点的写锁:

MATCH (n:X {id: 42})
SET n._LOCK_ = true
WITH n.prop as p
// ... operations depending on p, producing k
SET n.prop = k + 1
REMOVE n._LOCK_

在读取 n.prop 之前添加一个无实际意义的SET n._LOCK_ 语句,它确保在读取操作之前获取写锁,并且不会由于该特定节点上所有并发查询的强制序列化而丢失更新。

3. 默认的加锁行为

  • 在节点或关系上添加、更改或删除属性时,将对特定节点或关系进行写锁定。
  • 创建或删除节点时,将为特定节点获取写锁。
  • 创建或删除关系时,将对特定关系及其两端的节点进行写锁定。

锁将被添加到事务中并在事务完成时释放。

4. 死锁

既然使用了锁,就有可能会发生死锁,但Neo4j 会在它们发生之前检测出来(由获取锁导致的死锁)并抛出异常。在这个异常被抛出之前,事务会被标记为回滚。事务获取的所有锁仍将被持有,但会在事务完成时释放(在前面指出的 finally 块中)。一旦锁被释放,等待锁(由被死锁的事务持有)的其他事务就可以继续进行。如果需要,用户可以重试导致死锁的事务执行的工作。

频繁的死锁往往意味着并发写入请求的正在以某种方式发生,即不可能在执行它们的同时满足预期的隔离和一致性。解决方案是确保并发更新以合理的方式发生。例如,给定两个特定节点(A 和 B),为每个事务以随机顺序添加或删除这两个节点的关系,当有两个或更多事务同时执行时将导致死锁。一种选择是确保更新总是以相同的顺序发生(首先是 A,然后是 B)。另一种选择是确保每个线程/事务不会像其他并发事务那样对节点或关系进行任何有冲突的写入。例如,可以通过让单个线程执行特定类型的所有更新来实现。

使用 Neo4j 管理的锁之外的其他同步导致的死锁仍然可能发生。由于 Neo4j API 中的所有操作都是线程安全(thread safe)的,除非另有说明,因此不需要外部同步。其他需要同步的代码应该以这样的方式同步,即它永远不会在同步的块中执行任何 Neo4j 操作。

4.1.死锁处理示例

下面,您将找到如何在过程、服务器扩展或使用 嵌入式Neo4j时处理死锁的示例。

完整源代码可以在 DeadlockDocTest.java 中找到。

在处理代码中的死锁时,您可能需要解决几个问题:

  • 只进行有限数量的重试,如果达到阈值则失败。
  • 在每次尝试之间暂停以允许其他事务在再次尝试之前完成。
  • 重试循环不仅可用于死锁,还可用于其他类型的瞬态错误。

下面是一个示例,说明如何实现这一点。

示例 6. 使用重试循环处理死锁

这个例子展示了如何使用重试循环来处理死锁:

Throwable txEx = null;
int RETRIES = 5;
int BACKOFF = 3000;
for ( int i = 0; i < RETRIES; i++ )
{
    try ( Transaction tx = databaseService.beginTx() )
    {
        Object result = doStuff(tx);
        tx.commit();
        return result;
    }
    catch ( Throwable ex )
    {
        txEx = ex;

        // Add whatever exceptions to retry on here
        if ( !(ex instanceof DeadlockDetectedException) )
        {
            break;
        }
    }

    // Wait so that we don't immediately get into the same deadlock
    if ( i < RETRIES - 1 )
    {
        try
        {
            Thread.sleep( BACKOFF );
        }
        catch ( InterruptedException e )
        {
            throw new TransactionFailureException( "Interrupted", e );
        }
    }
}

if ( txEx instanceof TransactionFailureException )
{
    throw ((TransactionFailureException) txEx);
}
else if ( txEx instanceof Error )
{
    throw ((Error) txEx);
}
else
{
    throw ((RuntimeException) txEx);
}

5. 删除语义

删除节点或关系时,将自动删除该实体的所有属性,但节点的关系不会删除。 Neo4j 强制执行一个约束(提交时),即所有关系都必须具有有效的开始节点和结束节点。实际上,这意味着尝试删除仍然具有关系的节点将在提交时引发异常。但是,只要在提交事务时不存在关系,就可以选择删除节点和附加关系的顺序。

删除语义可以总结如下:

  • 当一个节点或关系被删除时,它的所有属性都将被删除。
  • 当事务提交时,被删除的节点不能有任何关系。
  • 可以获取对尚未提交的、删除的关系或节点的引用。
  • 在节点或关系被删除(但尚未提交)之后,对节点或关系的任何写操作都将引发异常。
  • 在提交后尝试获取对已删除节点或关系的新引用或旧引用,将引发异常。

6. 创建唯一的节点

在许多用例中,实体之间需要一定程度的唯一性。例如,系统中可能只存在一个具有特定电子邮件地址的用户。如果多个并发线程都尝试创建用户,则会创建重复项。

以下是确保唯一性的主要策略,它们都适用于跨集群和单实例部署。

6.1.单线程

通过使用单个线程,没有两个线程甚至会尝试同时创建特定实体。在集群中,外部单线程客户端可以执行这样的操作。

6.2.获取或创建

定义唯一性约束并使用 Cypher MERGE 子句是获取或创建唯一节点的最有效方法。有关更多信息,请参阅使用Cypher和唯一性约束获取或创建唯一节点。

7. 事务事件

可以注册一个 neo4j.org.graphdb.event.TransactionEventListener 来接收 Neo4j 数据库事务事件。一旦它在 org.neo4j.dbms.api.DatabaseManagementService 实例上注册,它就会接收它注册的数据库的事务事件。侦听器会收到有关已执行的任何写操作、并将被提交的事务的通知。如果 Transaction#commit() 没有被调用,或者事务被 Transaction#rollback() 回滚,它将被回滚并且没有事件被发送到侦听器。

在提交事务之前,会调用侦听器的 beforeCommit 方法,并使用事务中所做修改的整个差异。此时事务仍在运行,因此仍然可以进行更改。该方法也可能抛出异常,这将阻止事务被提交。如果事务回滚,则会调用侦听器的 afterRollback 方法。

侦听器的执行顺序未定义 ,不能保证任何一个侦听器所做的更改会被其他侦听器收到。

如果 beforeCommit 在所有注册的侦听器中成功执行,则提交事务并使用相同的事务数据调用 afterCommit 方法。此调用还包括从 beforeCommit 返回的对象。

在 afterCommit 事务已关闭,访问 org.neo4j.graphdb.event.TransactionData 之外的任何内容都需要打开一个新事务。 Neo4j.org.graphdb.event.TransactionEventListener 收到有关通过 org.neo4j.graphdb.event.TransactionData 可访问的任何更改的事务的通知。某些索引和架构更改不会触发这些事件。

以下示例显示如何为特定数据库注册侦听器,并在事务更改集之上执行基本操作。

完整源代码可以在 TransactionEventListenerExample.java 中找到。

示例 7. TransactionEventListener 注册事务事件侦听器并检查更改集:

public static void main( String[] args ) throws IOException
{
    FileUtils.deleteDirectory( HOME_DIRECTORY );
    var managementService = new DatabaseManagementServiceBuilder( HOME_DIRECTORY ).build();
    var database = managementService.database( DEFAULT_DATABASE_NAME );

    var countingListener = new CountingTransactionEventListener();
    managementService.registerTransactionEventListener( DEFAULT_DATABASE_NAME, countingListener );

    var connectionType = RelationshipType.withName( "CONNECTS" );
    try ( var transaction = database.beginTx() )
    {
        var startNode = transaction.createNode();
        var endNode = transaction.createNode();
        startNode.createRelationshipTo( endNode, connectionType );
        transaction.commit();
    }
}

private static class CountingTransactionEventListener implements TransactionEventListener<CreatedEntitiesCounter>
{
    @Override
    public CreatedEntitiesCounter beforeCommit( TransactionData data, Transaction transaction, GraphDatabaseService databaseService ) throws Exception
    {
        return new CreatedEntitiesCounter( size( data.createdNodes() ), size( data.createdRelationships() ) );
    }

    @Override
    public void afterCommit( TransactionData data, CreatedEntitiesCounter entitiesCounter, GraphDatabaseService databaseService )
    {
        System.out.println( "Number of created nodes: " + entitiesCounter.getCreatedNodes() );
        System.out.println( "Number of created relationships: " + entitiesCounter.getCreatedRelationships() );
    }

    @Override
    public void afterRollback( TransactionData data, CreatedEntitiesCounter state, GraphDatabaseService databaseService )
    {
    }
}

private static class CreatedEntitiesCounter
{
    private final long createdNodes;
    private final long createdRelationships;

    public CreatedEntitiesCounter( long createdNodes, long createdRelationships )
    {
        this.createdNodes = createdNodes;
        this.createdRelationships = createdRelationships;
    }

    public long getCreatedNodes()
    {
        return createdNodes;
    }

    public long getCreatedRelationships()
    {
        return createdRelationships;
    }
}

Neo4j 中文开发者月刊 - 202209期 这是Neo4j中文开发者月刊的9月份的一期,订阅了邮件动态的伙伴是在10月8日收到。如果你想第一时间收到这份月刊,欢迎填写表单订阅。以下是月刊内容。 阅读详情

相关推荐

SpringBoot结合Neo4j

SpringBoot结合Neo4j一篇文章就搞定 假期无聊玩玩图数据库,顺便记录一下学习的收获。 文章目录SpringBoot结合Neo4j一篇文章就搞定前言一、环境以及相关配置二、业务逻辑代码 前言 实验室有知识图谱的项目,用到了图数据库,Neo4j的前置知识这里就不过多介绍了,这里直接讲解SpringBoot如何与Neo4j结合。 neo4j官网 Spring Data Neo4j 一、环境以及相关配置 这里不多说了,直接挂出来pom.xml文件,大家参考一下,注意版本。 springboot

qq_42265220的博客 6272

Neo4j-事务操作

​ 事务结束之前,任何数据都不会改变消失,只有事务结束了,数据才发生改变(持久性)。​ 当前事务操作的数据不允许被其他事务操作(隔离性)​ 事务要么全是或者全否(原子性)​ 事务只能提交有效数据(一致性)

Akun_2217的博客 664

Spring Data Neo4j 详尽教程:由浅入深掌握图数据库开发

图数据库是一种专门用于存储和查询节点(实体)及其关系的数据库。与传统关系型数据库不同,图数据库原生支持复杂关系的高效遍历,非常适合社交网络、知识图谱、推荐系统等场景。对象-图映射(OGM):将Java对象映射到图中的节点和关系Repository支持:类似Spring Data JPA,提供声明式数据访问接口与Spring Boot无缝集成:通过starter简化配置响应式编程支持:支持基于Reactive Streams的响应式访问使用@Node@Id。

步子哥的博客 1106

Neo4j数据库的事务

1.事务管理 为了保持数据的完整性和保证良好的事务行为,Neo4j也支持ACID特性: (1).原子性:一整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 (2).一致性:在事务开始之前和事务结束以后,数据库的完整性限制没有被破坏。  (3).隔离性:两个

7230

Neo4j 事务处理与数据一致性:深度解析与实践指南

读未提交(Read Uncommitted):这是最低的隔离级别,允许一个事务读取其他未提交事务的数据修改。可能会出现脏读、不可重复读和幻读现象,但在某些对数据一致性要求不高的场景下,可以获得较高的并发性能。读已提交(Read Committed):事务只能读取已提交数据,避免了脏读问题。这是大多数场景下的默认隔离级别,平衡了数据一致性和并发性能。可重复读(Repeatable Read):确保在同一个事务中,多次读取同一数据的结果一致。避免了脏读和不可重复读问题,但可能会出现幻读现象。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1202

大规模Neo4j集群中的因果一致性服务器

通过使用分布式共识算法,如Paxos或Raft,可以确保多个节点之间的修改操作能够以一致的方式应用到数据中。因果一致性是指在分布式系统中,当多个节点同时对数据进行修改时,系统能够保持数据的一致性。具体来说,在一个大规模Neo4j集群中,如果两个或多个节点同时对同一条数据进行修改,那么系统应该能够判断出这些修改的因果关系,并以一致的方式将它们应用到数据中。在大规模Neo4j集群中实现因果一致性可以采用多种方法,其中一种常见的方法是使用分布式共识算法,如Paxos或Raft。实现因果一致性的方法。

GnabVue的博客 224

解决 Spring Boot 多数据源环境下事务管理器冲突问题(非Neo4j请求标记了 @Transactional 尝试启动Neo4j的事务管理器)

在 Oracle 与 Neo4j 共存的多数据源项目中,一个仅涉及 Oracle 操作的请求,却因为 Neo4j 连接失败而报错。根本原因是 Spring 的默认事务管理器错误地指向了 Neo4j,导致不相关的请求也受到了 Neo4j 连接状态的影响。

Anarkh_Lee的博客 1559

Spring Data Neo4j事务管理与JavaFX CDI集成实战

Spring Data Neo4j支持许多JPA注解来定义查询,例如:@Query:可以标注在实体类的方法上,用来指定自定义的查询语句。@Param:用来传递查询参数,可以和@Query注解结合使用。@Id:用来指定实体的唯一标识符属性。:用来从查询结果中提取特定的列。一个使用@Query注解的简单例子如下:在这个例子中,我们定义了一个根据姓名查找Person实体的方法,并使用了@Param注解来传递参数。

weixin_42160645的博客 412

Neo4j事务管理:ACID实现、锁机制与并发控制实战

事务特性描述Neo4j实现方式原子性事务内的所有操作要么全部成功,要么全部失败通过事务日志和回滚机制实现原子性一致性事务结束时,数据库的约束得到遵守通过约束和验证确保数据的一致性隔离性事务间互不干扰,确保每个事务执行的结果一致默认使用串行化隔离级别,避免并发冲突持久性事务提交后,数据不可丢失使用WAL(Write-Ahead Logging)确保持久性Neo4j 的事务管理机制结合了 ACID 特性、锁机制和并发控制策略,确保了图数据在并发环境下的一致性、可靠性和高效性。

一碗黄焖鸡三碗米饭的博客 909

红外基本数据观察需要用到的技巧

1.用ps查看Y8的数据,直接将Y8.raw格式拖动到ps中去。 2.用ps查看Y16数据,直接将Y16.raw拖动到PS中去。 3.Y16转Y8是将Y16的值(Y16的范围~32768–32767)映射到Y8的值(Y8的范围为0~255),步骤如下:1.按照Y16的大小排列并统计相同Y16出现的次数直方图; 2.根据抛点比例计算抛点个数,分别从前往后与从后往前...

阿锋的专栏 2629

第二十届全国大学生智能车竞赛-地瓜机器人智慧医疗挑战赛技术解析与实战指南

本文深入解析了第二十届全国大学生智能车竞赛-地瓜机器人智慧医疗挑战赛的核心技术。内容涵盖从零搭建数字孪生环境、实现AI视觉任务(二维码识别、引导线追踪、目标检测)、在边缘设备部署轻量化大模型进行图生文描述,到遥操作与自主控制的平滑切换,并提供了基于ROS2的系统集成与赛场实战指南,助力参赛者高效备赛。

weixin_29252171的博客 2770

neo4j入门

neo4j入门,Springboot整合neo4j,Springboot高版本整合neo4j,Springboot cql操作neo4j接收动态参数,neo4j只有return才会执行,neo4j和mysql事务冲突

zengzl1215的博客 1万+

QT的温湿度显示系统

大家好,这里是石侃侃的博客,欢迎前来讨论这篇文章介绍的是DHT11在2440上的基于Qt5.6的应用基于单片机系统的温湿度监测系统构成框图如图2-1所示。图2-1 系统构成框图该系统采用单片机s3c2440作为了本设计的核心元件。利用LCD作为了显示器件,利用触摸屏作为用户界面输入设备,第一行显示当前实时的温度,湿度,第二行依次显示历史时刻最高的温度值,最高的湿度值。第三行是一个文本框,记录了程...

zxpcus的博客 1万+

py2neo和neo4j

无论选择哪一个,都可以根据个人的偏好和项目的需求进行选择。在实际应用中,两者都是被广泛使用的。是两个 Python 中与 Neo4j 图数据库交互的库,但它们有不同的设计和使用方式。对象表示图数据库中的节点和关系,使得代码更加直观和易读。更加 Pythonic。官方提供的官方驱动库。

qq_41081716的博客 1298

别再花屏了!手把手教你用STM32CubeIDE搞定LVGL 8.3移植(附完整源码)

本文详细介绍了如何在STM32CubeIDE环境下成功移植LVGL 8.3,解决常见的花屏问题。从环境配置、显示驱动优化到编译警告处理,提供完整的实战方案和源码示例,帮助开发者快速实现流畅的嵌入式GUI界面。特别针对STM32平台的DMA2D加速和内存管理进行了深度优化。

weixin_33739646的博客 242

黑猫带你学UFS协议第17篇:UFS安全模式详解(Secure Mode)

本文详细介绍了UFS协议中的安全模式,包括Erase, Discard, Purge和Wipe Device操作。Erase用于永久删除数据并确保无法恢复;Discard不保证数据清除;Purge类似于Sanitize,清除内部未映射的物理块数据;Wipe Device则是格式化设备。这些操作涉及逻辑单元、擦除单位、相关寄存器配置等,确保数据安全。" 126036669,12409270,MySQL 8.0 开窗函数详解,"['数据库理论', 'SQL']

黑猫奥利奥的博客 2559

Neo4j 事务管理器冲突导致 MySQL 事务失效 — 排查与修复技术文档

项目同时引入 Spring Data Neo4j 与 MySQL 时,Neo4j 自动配置抢先注册了 `Neo4jTransactionManager`,导致 JDBC 事务管理器因 `@ConditionalOnMissingBean` 条件不满足而从未创建。此后所有未显式指定事务管理器的 `@Transactional` 实际开启的都是 Neo4j 事务,对 MySQL 连接毫无约束(`autoCommit=true`),异常后无法回滚,产生脏数据。

生如夏花的博客 424

《QGIS快速入门与应用基础》079:KML/KMZ格式:Google Earth兼容

KML/KMZ是专为地理可视化设计的空间数据格式,原生兼容Google Earth,支持点线面要素标注与多媒体集成。KML为XML文本格式,KMZ是其压缩版本。该格式优势在于可视化表现力强、跨平台共享便捷,适合地理标注、路线分享等场景,但存在属性支持弱、大数据量处理效率低等局限。QGIS中可便捷加载和导出KML/KMZ数据,需注意编码设为UTF-8、勾选"导出样式"以保留可视化效果。建议中小规模标注数据使用KMZ格式,确保关联资源完整,提升共享效率。

LuckyHanMo的博客 768

Python操作Neo4j,py2neo 和 neo4j 两个库的区别

是的,py2neo和neo4jPython 库都可以用来操作 Neo4j 数据库,但它们之间有一些区别。py2neo在选择哪个库时,你应该考虑你的特定需求。如果你需要更丰富的功能和更易于使用的接口,可能会倾向于使用py2neo。而如果你需要最佳的性能和官方支持,那么使用neo4j官方客户端可能是更好的选择。下面提供一些基本的代码示例来展示如何使用py2neo和neo4j这两个库来连接和操作 Neo4j 数据库。

sagima_sdu的博客 2086

【某音电商】protobuf聊天协议逆向

某音电商私信、聊天消息protobuf协议逆向分析与解析

吴秋霖的博客 2314

【即插即用模块】注意力篇 | TGRS 2025 | MFA聚特征+HPDown保细节+HFF融层级,三大模块各司其职,性能翻倍!

本文介绍了MTMLNet网络中的三大核心模块:MFA(多阶段特征聚合)、HPDown(混合池化下采样)和HFF(分层特征融合)。MFA通过双尺度深度卷积和注意力机制增强特征提取能力;HPDown结合平均池化和最大池化,有效保留下采样过程中的特征信息;HFF采用三注意力机制实现自适应特征融合。这三个模块协同工作,在红外小目标检测与分割任务中取得了SOTA效果。实验表明,各模块在特征提取、信息保留和融合方面均优于传统方法,可灵活应用于各类视觉任务中。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 285

neo4j springboot 日志_springboot使用neo4j

springboot2.2使用neo4j第一次更新先放一些代码进来,下次加注释1.引入相应的包org.springframework.bootspring-boot-starter-data-neo4j2.配置neo4jspring.data.neo4j.uri=bolt://localhost:7687spring.data.neo4j.username=neo4jspring.data.neo...

weixin_39795268的博客 559

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Spring Data Neo4j

Spring Data Neo4j官网学习地址Spring Data Neo4j简称SDN,SDN建立在Neo4j OGM基础之上,使用SDN可以帮助简化OGM的使用,更加容易与Spring框架整合应用。SDN 完全依赖于 Neo4j Java 驱动程序,而无需在映射框架和驱动程序之间引入另一个“驱动程序”或“传输”层。Neo4j Java 驱动程序(有时称为 Bolt 或 Bolt 驱动程序)用作协议,与 JDBC 用于关系数据库非常相似。SDN 是一个对象图映射 (OGM) 库。

缘友一世的博客 1388

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Spring Boot项目里Neo4j和MySQL事务冲突了?手把手教你配置双数据源与事务管理器

本文深入探讨了Spring Boot项目中Neo4j与MySQL事务冲突的解决方案,提供了从基础配置到高级优化的完整指南。通过显式声明事务管理器、隔离双数据源事务以及最佳实践策略,帮助开发者有效解决多数据源整合中的事务管理难题,确保数据一致性与系统稳定性。

weixin_34098209的博客 303

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

neo4j 开发记录

文章目录docker搭建拉取镜像启动使用docker-compose进行启动DockerFile 重新打包感觉启动后还要配置,是挺麻烦的,重新打包Springboot 使用neo4j语法创建节点创建关系删除查询 docker搭建 拉取镜像 docker pull neo4j 启动 docker run -d --name myneo4j \ -p 7474:7474 -p 7687:7687 \ -v /home/neo4j/data:/data \ -v /home/neo4j/logs:/logs

用针戳左手中指指头的博客 747

聊聊Neo4j图数据库的那些明显优势

引言:Neo4j是一个NoSQL的图数据库管理系统,像其他NoSQL数据库一样具有高效的查询性能。同时,Neo4j还具有完全事务管理特性,完全支持ACID事务管理。Neo4j与其他数据库相比,具有哪些明显的优势呢? 本文选自《Neo4j全栈开发》。   在高速发展的互联网应用中,业务需求的频繁变更和数据的快速增长都要求数据库必须具有很强的适应能力。Neo4j图数据库正是一个能够适应这种...

博文视点(北京)官方博客 5247
上一篇: 幕后花絮:世界上最大的分布式图数据库是怎样炼成的?
下一篇: 鲲鹏920+OpenEuler+毕昇JDK:Neo4j信创兼容性测试
俞博士
俞博士 领域专家: 数据库技术领域 领域专家: 数据库技术领域 业界专家认证 业界专家认证
博客等级 码龄9年 2326粉丝 72原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值