高级连接信息

连接 URI

驱动程序支持连接到以下格式的 URI:

<SCHEME>://<HOST>[:<PORT>[?policy=<POLICY-NAME>]]
  • <SCHEME>neo4jneo4j+sneo4j+sscboltbolt+sbolt+ssc 中的一个。

  • <HOST> 是 Neo4j 服务器所在的主机名。

  • <PORT> 是可选的,表示 Bolt 协议可用的端口。

  • <POLICY-NAME> 是可选的服务器策略名称。服务器策略在使用前需要先进行设置。

驱动程序不支持连接到嵌套路径,例如 example.com/neo4j/。必须能够从域名根目录访问服务器。

连接协议与安全性

驱动程序与服务器之间的通信由 Bolt 进行中介。服务器 URI 的方案(scheme)决定了连接是否加密,以及如果加密,接受何种类型的证书。

URL 方案 加密 注释

neo4j

本地设置的默认值

neo4j+s

(仅限 CA 签名的证书)

Aura 的默认值

neo4j+ssc

(CA 签名和自签名证书)

无论实例是适当的集群环境还是单机环境,驱动程序在成功连接后都会从服务器接收一张路由表。驱动程序的路由行为通过将读/写事务引导至适当的集群成员,与 Neo4j 集群配合工作。如果您想针对特定机器,请改用 boltbolt+sbolt+ssc URI 方案。

要使用的连接方案并非由您选择,而是由服务器要求决定的。您必须预先知道正确的服务器方案,因为在连接之前不会公开任何元数据。连接方案是实例 URI 的一部分。如果不确定,请咨询数据库管理员。

身份验证方法

基本身份验证(默认)

基本身份验证方案依赖于传统的用户名和密码。

await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Basic(dbUser, dbPassword));

基本身份验证方案也可用于针对 LDAP 服务器进行身份验证(仅限企业版)。

Kerberos 身份验证

Kerberos 身份验证方案需要一个 base64 编码的票据。只有在服务器安装了 Kerberos 插件的情况下才能使用。

await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Kerberos(ticket));

Bearer 令牌身份验证

Bearer 身份验证方案需要一个由身份提供商通过 Neo4j 的 单点登录(SSO)功能提供的 base64 编码令牌。

await using var driver = GraphDatabase.Driver(dbUri, AuthTokens.Bearer(ticket));

自定义身份验证

使用 AuthTokens.Custom() 登录具有自定义身份验证方案的服务器。

await using var driver = GraphDatabase.Driver(
    dbUri,
    AuthTokens.Custom(principal, credentials, realm, scheme, parameters)
);
// `parameters` is optional

无身份验证

如果服务器上禁用了身份验证,则可以完全省略身份验证参数。

轮换身份验证令牌

可以轮换预期会过期的身份验证令牌(例如 SSO)。运行时间长于令牌有效期的事务将继续运行,而无需重新进行身份验证,而同一会话中的不同事务可能在不同的身份验证令牌下工作。

要处理轮换令牌,您需要在实例化 IDriver 时提供一个 IAuthTokenManager 实例,而不是静态身份验证令牌。最简单的入门方法是使用 内置的 AuthTokenManagers 实现之一AuthTokenManagers 使用 AuthTokenAndExpiration 对象。

轮换每 60 秒过期的 Bearer 令牌
await using var driver = GraphDatabase.Driver(
    dbUri,
    AuthTokenManagers.Bearer(GetTokenAsync));

Task<AuthTokenAndExpiration> GetTokenAsync() {
    var token = getToken();

    // Assume we know tokens expire every 60 seconds
    var expiresIn = 60 * 1000;
    // Include a little buffer so that new token is fetched before the old one expires
    expiresIn -= 10_000;

    return Task.FromResult(new AuthTokenAndExpiration(token, expiresIn));
}

// Some way to get a token
string getToken() {
    return "token-string";
}
此功能不得用于切换用户。身份验证管理器必须始终返回相同身份的令牌。您可以在 查询级别会话级别 切换用户。
IAuthTokenManager 对象不得以任何方式与驱动程序交互,因为这可能导致死锁和未定义的行为。

双向 TLS(客户端证书作为双因素认证)

双向 TLS (mTLS) 允许您使用客户端证书作为向服务器进行身份验证的第二因素。除非服务器上禁用了身份验证,否则该证书只能与身份验证令牌一起使用,不能替代常规身份验证。

客户端的证书和公钥必须放置在服务器的 <NEO4J_HOME>/certificates/bolt/trusted 目录中。有关服务器设置的更多信息,请参阅 配置 Bolt 上的 SSL

要使 mTLS 工作,驱动程序与服务器的连接必须加密,即 连接 URI 方案 必须为 +s+ssc(例如 neo4j+s://example.com:7687)。

使用配置方法 WithClientCertificateProvider() 提供一个 IClientCertificateProvider
您的实现必须提供一个线程安全的 GetCertificateAsync() 方法,返回一个 ValueTask<X509Certificate2>

using System.Security.Cryptography.X509Certificates;

class ClientCertificateProvider {

    public async ValueTask<X509Certificate2> GetCertificateAsync() {
        string certPath = "path/to/cert.pem";
        string certPassword = "password";

        X509Certificate2 certificate = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.MachineKeySet);
        return await Task.FromResult(certificate);
    }

}

await using var driver = GraphDatabase.Driver(
    dbUri,
    AuthTokens.Basic(dbUser, dbPassword),
    conf => conf.WithClientCertificateProvider(ClientCertificateProvider)
);
await driver.VerifyConnectivityAsync();

日志记录

要启用日志记录,请在创建 Driver 对象时使用 .withLogger(INeo4jLogger) 配置方法,并提供一个 ILogger 的实现。

通过 INeo4jLogger 的示例实现启用调试日志记录
using Neo4j.Driver;

const string dbUri = "<database-uri>";
const string dbUser = "<username>";
const string dbPassword = "<password>";

var logger = new Neo4jLogger();
logger.EnableDebug();

await using var driver = GraphDatabase.Driver(
    dbUri, AuthTokens.Basic(dbUser, dbPassword),
    conf => conf.WithLogger(logger)
);
await driver.VerifyConnectivityAsync();


public class Neo4jLogger : INeo4jLogger {

    private bool debug = false;
    private bool trace = false;

    public void Log(string level, string message) {
        DateTime localDate = DateTime.Now;
        Console.WriteLine($"{localDate.TimeOfDay} {level} {message}");
    }

    public void Error(Exception cause, string message, params object[] args) {
        this.Log("ERROR", String.Format($"{message}", args));
    }
    public void Warn(Exception cause, string message, params object[] args) {
        this.Log("WARN", String.Format($"{message}", args));
    }

    public void Info(string message, params object[] args) {
        this.Log("INFO", String.Format($"{message}", args));
    }

    public void Debug(string message, params object[] args) {
        this.Log("DEBUG", String.Format($"{message}", args));
    }

    public void Trace(string message, params object[] args) {
        this.Log("TRACE", String.Format($"{message}", args));
    }

    public void EnableDebug() {
        this.debug = true;
    }

    public void EnableTrace() {
        this.trace = true;
    }

    public bool IsTraceEnabled() {
        return this.trace;
    }

    public bool IsDebugEnabled() {
        return this.debug;
    }
}
成功连接后的日志输出示例
12:34:27.3134245 DEBUG [conn-localhost:7687-1] ~~ [CONNECT] neo4j://:7687/
12:34:27.3322335 DEBUG [conn-localhost:7687-1] C: [HANDSHAKE] 60 60 B0 17 00 07 07 05 00 02 04 04 00 00 01 04 00 00 00 03
12:34:27.3336518 DEBUG [conn-localhost:7687-1] S: [HANDSHAKE] 5.7
12:34:27.3523440 DEBUG [conn-localhost:7687-1] C: HELLO [{user_agent, neo4j-dotnet/5.27}, {routing, [{address, localhost:7687}]}, {bolt_agent, [{product, neo4j-dotnet/5.27.38}, {platform, Linux Mint 22.1;X64}, {language_details, .NET 8.0.16}]}]
12:34:27.3526200 DEBUG [conn-localhost:7687-1] C: LOGON [{scheme, basic}, {principal, neo4j}, {credentials, ******}]
12:34:27.3599672 DEBUG [conn-localhost:7687-1] S: SUCCESS [{server, Neo4j/2025.06.0-30853}, {connection_id, bolt-228}, {hints, [{connection.recv_timeout_seconds, 120}]}]
12:34:27.3650548 DEBUG [conn-localhost:7687-1] Connection 'conn-localhost:7687-1' renamed to 'bolt-228'. The new name identifies the connection uniquely both on the client side and the server side.
12:34:27.3655529 DEBUG [bolt-228] S: SUCCESS []
12:34:27.3714612 DEBUG [bolt-228] C: RESET
12:34:27.3745223 DEBUG [bolt-228] S: SUCCESS []
12:34:27.3806841 DEBUG [bolt-228] C: ROUTE { 'address':'localhost:7687' } [] { }
12:34:27.3823965 DEBUG [bolt-228] S: SUCCESS [{rt, [{servers, [[{addresses, [localhost:7687]}, {role, WRITE}], [{addresses, [localhost:7687]}, {role, READ}], [{addresses, [localhost:7687]}, {role, ROUTE}]]}, {ttl, 300}, {db, neo4j}]}]
12:34:27.3888866 DEBUG [bolt-228] C: RESET
12:34:27.3893542 DEBUG [bolt-228] S: SUCCESS []
12:34:27.3917428 INFO Routing table is updated => RoutingTable{database=neo4j, routers=[neo4j://:7687/], writers=[neo4j://:7687/], readers=[neo4j://:7687/], expiresAfter=300s}
12:34:27.3918886 DEBUG [bolt-228] C: RESET
12:34:27.3922620 DEBUG [bolt-228] S: SUCCESS []
12:34:27.3949034 DEBUG [pool-localhost:7687] Disposing Available Connection bolt-228
12:34:27.3961484 DEBUG [bolt-228] C: GOODBYE

自定义地址解析器

创建 IDriver 对象时,您可以指定一个解析器函数来解析驱动程序初始化时所使用的连接地址。请注意,驱动程序在路由表中接收到的地址不会通过自定义解析器进行解析。

您可以通过 .WithResolver() 配置方法指定解析器,该方法使用 IServerAddressResolver 对象。

解析后的地址必须具有相同的端口和 URI 方案。在下例中,驱动程序使用 neo4j:// URI 方案和 7687 端口进行初始化,因此在 dbUri 中提供的解析地址也必须在 neo4j://7687 端口上可用。

连接到 example.com 被解析为 localhost
using Neo4j.Driver;

const string dbUri = "localhost";  // omit scheme and port
const string dbUser = "<username>";
const string dbPassword = "<password>";

// setting a port different than the one given in `driver` won't work
var address = ServerAddress.From(dbUri, 7687);

await using var driver = GraphDatabase.Driver(
    "neo4j://example.com:7687",
    AuthTokens.Basic(dbUser, dbPassword),
    conf => conf.WithResolver(new ListAddressResolver(address))
);
await driver.VerifyConnectivityAsync();

class ListAddressResolver : IServerAddressResolver {
    private readonly ServerAddress[] _servers;

    public ListAddressResolver(params ServerAddress[] servers) {
        _servers = servers;
    }

    public ISet<ServerAddress> Resolve(ServerAddress address) {
        return new HashSet<ServerAddress>(_servers);
    }
}

禁用遥测

如果服务器有要求,驱动程序可以将匿名使用统计信息发送到其连接的服务器。遥测在服务器端通过配置设置 server.bolt.telemetry.enabled 进行管理。默认情况下,自管理实例上的遥测是禁用的,Aura 实例上的遥测是启用的。

通过在连接时使用 .WithTelemetryDisabled(),驱动程序将永远不会发送任何遥测数据。

在驱动程序端禁用遥测
await using var driver = GraphDatabase.Driver(
    dbUri,
    AuthTokens.Basic(dbUser, dbPassword),
    conf => conf.WithTelemetryDisabled());

有关传输了哪些信息的更多信息,请参阅 API 文档 → .WithTelemetryDisabled()

其他连接参数

您可以在 API 文档 → ConfigBuilder 中找到所有 IDriver 配置参数。

术语表

LTS (长期支持版)

长期支持 (Long Term Support) 版本是保证在若干年内得到支持的版本。Neo4j 4.4 和 5.26 是 LTS 版本。

Aura

Aura 是 Neo4j 的全托管云服务。它提供免费和付费计划。

Cypher

Cypher 是 Neo4j 的图查询语言,允许您从数据库中检索数据。它就像 SQL,但专用于图数据库。

APOC

Awesome Procedures On Cypher (APOC) 是一个包含(许多)函数的库,这些函数在 Cypher 本身中难以轻松实现。

Bolt

Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。默认监听 7687 端口。

ACID

原子性 (Atomicity)、一致性 (Consistency)、隔离性 (Isolation)、持久性 (Durability) (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保即使发生故障,数据库中的数据也能保持准确和一致。

最终一致性

如果一个数据库能保证所有集群成员在某个时间点都存储了数据的最新版本,则该数据库具有最终一致性。

因果一致性

如果读写查询被集群中的每个成员以相同的顺序看到,则数据库具有因果一致性。这比最终一致性更强。

NULL

空标记不是一种类型,而是缺失值的占位符。更多信息,请参阅 Cypher → 使用 null

事务

事务是一个工作单元,要么被提交,要么在失败时被回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或全部撤销,以避免钱从一个账户扣除却未存入另一个账户的情况。

背压

背压是对数据流的抵抗力。它确保客户端不会被过快发送的数据压垮,从而超出其处理能力。

书签

书签是代表数据库某种状态的标记。通过将一个或多个书签与查询一起传递,服务器将确保在所表示的状态建立之前,该查询不会被执行。

事务函数

事务函数是由 .ExecuteReadAsync().ExecuteWriteAsync() 调用执行的回调。如果服务器发生故障,驱动程序会自动重新执行回调。

IDriver

IDriver 对象保存了与 Neo4j 数据库建立连接所需的详细信息。