Java
本节介绍通过驱动连接并通过 Java 程序操作 VexDB 的方式,并提供了示例代码以供参考。
Java 数据库连接(Java Database Connectivity,简称 JDBC)是 Java 语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
vexdb-jdbc 数据库驱动程序是一个能够支持基本 SQL 功能的通用应用程序编程接口,支持一般的 SQL 数据库访问。通过驱动程序,用户可以在应用程序中实现对 VexDB 数据库的连接与访问。
配置 JDBC 驱动
在使用 JDBC 连接 VexDB 数据库前,需要配置 JDBC 驱动。
设置类路径
- 通过 JDBC 进行连接之前,请先获取 JDBC 驱动包。
要使用驱动, 必须将驱动 jar 包含在类路径里,可以将jar包路径添加到CLASSPATH 环境变量中,或者使用 java 命令行标记的方式将驱动jar包引入。比如,有一个使用 VexDB JDBC 驱动的应用安装在 /usr/local/lib/myapp.jar,而 VexDB JDBC驱动安装在 /usr/local/vexdb/java/。可以用以下方式运行应用:
export CLASSPATH=/usr/local/lib/MyApp.jar:/usr/local/vexdb/java/VexDB$shape_jdbc_$version<v|p>_$buildtime.jar.java MyApp
不同版本的 jar 包名称可能不同,请以实际情况为准。 - 在集成开发环境中配置 JDBC 驱动:
以在 IDEAJ Community 中配置为例。
1)配置 SDK。
在 IDEAJ 中配置工程的 JDK 1.8,如下图所示。
2)导入 VexDB JDBC 包。
在 IDEAJ 中导入 jar 包,如下图所示。
配置为可接受 TCP/IP连接
由于 java 只支持使用 TCP/IP 连接,所以 VexDB 必须配置为可接受 TCP/IP 连接。可以通过修改 listen_addresses 来进行配置。
vi postgresql.conf
修改 listen_address 参数。
listen_address = '*'
配置认证文件
需要配置 VexDB 的主机认证文件,保证客户端程序可以访问数据库。
vi pg_hba.conf
添加以下内容:
host all all 0.0.0.0/0 md5
连接数据库
- 导入 java.sql 包。
任何使用 JDBC 的程序都需要导入java.sql包:import java.sql.*
- 加载驱动。
在试图与数据库建立连接之前,首先需要加载驱动,加载驱动有两种方法:
在代码中,用Class.forName(Driver)方法加载驱动,例如:Class.forName("com.vexdb.Driver");
在 JVM 启动时作为参数传递,例如:java -Djdbc.drivers=com.vexdb.Driver
- 连接 URL 格式
使用 VexDB JDBC驱动访问 VexDB 的URL格式如下:- jdbc:vexdb://host:port/database
- jdbc:vexdb://host:port/
- jdbc:vexdb://host/database
- jdbc:vexdb://host/
- jdbc:vexdb:/
- jdbc:vexdb://host:port/database?param1=value1¶m2=value2
URL中各参数的含义如下:- host
服务端的主机名,默认为 localhost。如果要指定 IPV6 的地址,必须用方括号括起主机参数,例如:jdbc:vexdb://::1:5432/postgres。 - port
服务端监听的端口,默认为 5432。 - database
数据库名称,默认连接的数据库是与用户同名的数据库。比如连接用户为vbuser,如果不指定database参数,则默认连接到vbuser这个数据库。 - param1
连接串参数,可参考连接参数中的表格。 - value
连接串参数的取值,可参考连接参数中的表格,未指定时使用默认值。
- 获取 JDBC 连接。
使用 DriverManager.getConnection() 获取连接:Connection connection = DriverManager.getConnection(url,username,password);
- 关闭 JDBC 连接。
关闭连接时调用Connection的close()方法即可:Connection connection = DriverManager.getConnection(url,username,password); connection.close();
连接参数
参数名称 | 参数类型 | 参数说明 |
---|---|---|
PGDBNAME | String | 指定用于连接的数据库名称(可直接在 JDBC URL 中指定),默认值为空。 |
PGHOST | String | 指定数据库服务的主机名称(可直接在 JDBC URL 中指定),默认值为空。 |
PGPORT | String | 指定数据库服务的端口号(可直接在 JDBC URL 中指定),默认值为空。 |
user | String | 连接数据库的用户。 |
password | String | 数据库用户的密码。 |
protocolVersion | String | 连接协议版本号,目前仅支持 3。注意:设置该参数时将采用 md5 加密方式,需要同步修改数据库的加密方式:vb_guc set -N all -I all -c password_encryption_type=1 ,重启 VexDB 生效后需要创建用 md5 方式加密口令的用户。同时修改 pg_hba.conf,将客户端连接方式修改为 md5。用新建用户进行登录(不推荐)。默认值为空。 |
enable_ce | String | 指定是否开启客户端加密特性,取值为 '1' 时用于打开此特性,默认值为空。 |
loggerLevel | String | 指定驱动的日志级别,默认值为空,目前支持4种级别:OFF、INFO、DEBUG、TRACE。设置为 OFF 关闭日志,设置为 INFO、DEBUG 和 TRACE 记录的日志信息详细程度不同。默认值为 INFO。该参数设置值不区分大小写。 |
loggerFile | String | 指定驱动的日志输出的文件名称,默认值为空。 |
logger | String | 指定第三方程序使用的日志,默认为空。 |
prepareThreshold | Integer | 指定使用 PreparedStatement() 构造的 SQL 语句在重复执行多少次后会缓存在数据库服务端,默认值为 5,即执行5次后会把查询计划等信息缓存到数据库端,随后的请求指挥发送该语句缓存后的句柄,建议使用默认值。 |
preparedStatementCacheQueries | Integer | 确定每个连接中缓存的查询数,默认情况下是 256。若在 prepareStatement() 调用中使用超过 256 个不同的查询,则最近最少使用的查询缓存将被丢弃。0 表示禁用缓存。建议使用默认值。 |
preparedStatementCacheSizeMiB | Integer | 确定每个连接可缓存的最大值(以兆字节为单位),默认情况下是 5。若缓存了超过 5 MB 的查询,则最近最少使用的查询缓存将被丢弃。0表示禁用缓存。建议使用默认值。 |
databaseMetadataCacheFields | Integer | 指定每个连接要缓存的最大字段数,当取值为 0 会禁用该缓存,默认值为 65536。 |
databaseMetadataCacheFieldsMiB | Integer | 指定每个连接要缓存的字段的最大值(MB),当取值为 0 会禁用该缓存,默认值为 5。 |
defaultRowFetchSize | Integer | 确定一次 fetch 在 ResultSet 中读取的行数。限制每次访问数据库时读取的行数可以避免不必要的内存消耗,从而避免 OutOfMemoryException。默认值是 0,这意味着 ResultSet 中将一次获取所有行,没有负数。 |
binaryTransfer | Boolean | 使用二进制格式发送和接收数据,默认值为 false。 |
readOnly | Boolean | 将连接设置为只读模式。 |
binaryTransferEnable | String | 指定以逗号分隔的二进制传输启用的类型列表,可以是 OID 编号或名称,默认值为空。 |
binaryTransferDisable | String | 指定以逗号分隔的二进制传输禁用的类型列表,可以是 OID 编号或名称,设置本参数取值后可以覆盖驱动程序默认设置中的值和通过参数 binaryTransferEnable 设置的值,默认值为空。 |
stringtype | String | 设置通过 setString() 方法使用的PreparedStatement() 参数的类型,可选字段为:false、 unspecified、 varchar。 如果 stringtype 设置为 VARCHAR(默认值),则这些参数将作为 varchar 参数发送给服务器。若 stringtype 设置为 unspecified,则参数将作为 untyped 值发送到服务器,服务器将尝试推断适当的类型。 |
unknownLength | Integer | 默认为 Integereger.MAX_VALUE。某些 postgresql 类型(例如 TEXT)没有明确定义的长度,当通过 ResultSetMetaData.getColumnDisplaySize 和 ResultSetMetaData.getPrecision 等函数返回关于这些类型的数据时,此参数指定未知长度类型的长度。 |
logUnclosedConnections | Boolean | 客户端可能由于未调用 Connection 对象的 close() 方法而泄漏 Connection 对象。最终这些对象将被垃圾回收,并且调用 finalize() 方法。如果调用者自己忽略了此操作,该方法将关闭 Connection。 |
disableColumnSanitiser | Boolean | 指定是否启用禁用列名净化的优化器,默认值为 false。 |
ssl | Boolean | 以 SSL 方式连接。ssl=true 可支持 NonValidatingFactory 通道和使用证书的方式:1、NonValidatingFactory 通道需要配置用户名和密码,同时将 SSL 设置为 true。2、配置客户端证书、密钥、根证书,将 SSL 设置为 true。 |
sslmode | Boolean | SSL 认证方式。取值范围为:disable、allow、prefer、require、verify-ca、verify-full。 disable:不使用 SSL 安全连接。allow:如果数据库服务器要求使用,则可以使用 SSL 安全加密连接,但不验证数据库服务器的真实性。prefer:如果数据库支持,那么首选使用 SSL 连接,但不验证数据库服务器的真实性。require:只尝试 SSL 连接,如果存在 CA 文件,则应设置成 verify-ca 的方式验证。verify-ca:只尝试 SSL 连接,并且验证服务器是否具有由可信任的证书机构签发的证书。verify-full:只尝试 SSL 连接,并且验证服务器是否具有由可信任的证书机构签发的证书,以及验证服务器主机名是否与证书中的一致。 |
sslfactory | String | 提供的值是 SSLSocketFactory 在建立 SSL 连接时用的类名。 |
sslfactoryarg | String | 此值是上面提供的 sslfactory 类的构造函数的可选参数(不推荐使用)。 |
sslhostnameverifier | String | 主机名验证程序的类名。 |
sslcert | String | 提供证书文件的完整路径。客户端和服务端证书的类型为 End Entity。 |
sslkey | String | 提供密钥文件的完整路径。使用时将客户端证书转换为 DER 格式:openssl pkcs8 -topk8 -outform DER -in client.key -out client.key.pk8 -nocrypt |
sslrootcert | String | SSL 根证书的文件名。根证书的类型为 CA。 |
sslpassword | String | sslpassword:String 类型。提供给 ConsoleCallbackHandler 使用。 |
sslprivatekeyfactory | String | 客户端密钥 ssl 的 factory,默认值为空。 |
sslpasswordcallback | String | SSL 密码提供者的类名。 |
tcpKeepAlive | Boolean | 启用或禁用 TCP 保活探测功能。默认为 false。 |
logInTimeout | Integer | 指建立数据库连接的等待时间。超时时间单位为秒。 |
connectTimeout | Integer | 使用的超时值或套接字连接操作,如果连接到服务器的时间超过该值,则连接断开。 |
socketTimeout | Integer 类 | 用于套接字读取操作的超时值。如果从服务器读取的时间超过此值,则连接将关闭。这既可以用作强力全局查询超时,也可以用作检测网络问题的方法。超时以秒为单位指定,值为零表示禁用。 |
cancelSignalTimeout | Integer | 发送取消消息本身可能会阻塞,此属性控制用于取消命令的connectTimeout和socketTimeout。超时时间单位为秒,默认值为 10 秒。 |
socketFactory | String | 用于创建与服务器 socket 连接的类的名称。该类必须实现了接口javax.net.SocketFactory,并定义无参或单 String 参数的构造函数。 |
socketFactoryArg | String | 此值是上面提供的 socketFactory 类的构造函数的可选参数,不推荐使用。 |
sendBufferSize | Integer | 该值用于设置连接流上的 SO_SNDBUF。 |
receiveBufferSize | Integer | 在连接流上设置 SO_RCVBUF。 |
assumeMinServerVersion | String | 客户端会发送请求进行 float 精度设置。该参数设置要连接的服务器版本,如 assumeMinServerVersion=9.0,可以在建立时减少相关包的发送。 |
ApplicationName | String | 设置正在使用连接的 JDBC 驱动的名称。通过在数据库主节点上查询 pg_stat_activity 表可以看到正在连接的客户端信息,JDBC 驱动名称显示在 application_name 列。默认值为 PostgreSQL JDBC Driver。 |
ApplicationType | String | 设置正在使用连接的 JDBC 驱动的类型。 |
jaasLogin | Boolean | 用于启用/禁用在进行身份验证之前通过 JAAS 登录获取 Gss 凭据的标志。 如果设置系统属性 javax.security.auth.useSubjectCredsOnly=false,则有效 或使用系统属性为 sun.security.jgss.native-true 的本机 GSS。 |
jaasApplicationName | String | 指定 JAAS 系统或应用程序登录配置的名称。 |
kerberosServerName | String | 使用 GSSAPl 进行身份验证时要使用的 kerberos 服务名称。这相当于 libpq 的 PGKRBSRVNAME 环境变量。 |
useSpnego | Boolean | 指定是否在 SSPI 身份验证请求中使用 spnego,默认值为 false,表示不使用。 |
gsslib | String | 指定强制 SSPI 或 GSSAPI,取值可以为 auto、sspi、gssapi,默认值为 auto。 |
sspiServiceClass | String | 指定用于 SPN 的 Windows SSPI 服务类,默认值为空。 |
allowEncodingChanges | Boolean | 设置该参数值为“true”时进行字符集类型更改,配合 characterEncoding 设置字符集。 |
currentSchema | String | 指定设置到 search-path 中的 schema。 |
targetServerType | String | 指定要连接的服务器类型,取值可以为 any、master、slave、preferSlave,默认值为 any。 any:连接到任意一个可用的数据库节点。master:连接到任意一个可写的数据库节点。slave:连接到任意一个只读的数据库节点。secondary:连接到任意一个只读的数据库节点。preferSlave:连接到任意一个只读的数据库节点,如果没有可用的只读节点,则连接到可读可写节点。preferSecondary :连接到任意一个只读的数据库节点,如果没有可用的只读节点,则连接到可读可写节点。 |
priorityServers | Integer | 此值用于指定 url 上配置的前 n 个节点作为主集群被优先连接。默认值为 null。该值为数字,大于 0,且小于 url 上配置的 DN 数量。 |
usingeip | Boolean | 负载平衡时使用弹性 IP 地址,默认值为 true。 |
loadBalanceHosts | Boolean | 配合 targetServerType 使用,若为 true,则随机分配节点,若为 false,则按顺序分配节。 |
hostRecheckSeconds | Integer | 指定检查主机状态的周期,以防它们发生更改,单位是毫秒,默认值为 10。 |
forceTargetServerSlave | Boolean | 此值用于控制是否开启强制连接备机功能,并在集群发生主备切换时,禁止已存在的连接在升主备机上继续使用。 默认值为 false,表示不开启强制连接备机功能。true 表示开启强制连接备机功能。 |
preferQueryMode | String | 用于指定执行查询的模式,共有 4 种取值:"extended"、"extendedForPrepared"、"extendedCacheEverything"和"simple"。 simple 模式会 excute,不 parse 和 bind;extended 模式会 bind 和 excute;extendedForPrepared 模式为 prepared statement 扩展使用;extendedCacheEverything 模式会缓存每个 statement。 |
autosave | String | 如果查询失败,指定驱动程序应该执行的操作。共有 3 种取值:"always"、 "never"、 "conservative"。 在 autosave=always 模式下,JDBC 驱动程序在每次查询之前设置一个保存点,并在失败时回滚到该保存点。说明将 autosave 设置为 always 可能会导致数据库内存溢出,不建议设置为 always。在 autosave=never 模式(默认)下,无保存点。在 autosave=conservative 模式下,每次查询都会设置保存点,但是只会在"statement XXX 无效"等情况下回滚并重试。 |
autoBalance | String | jdbc 可以通过 URL 中设置多个数据库节点,实现对主备集群的访问。通过设置负载均衡算法,jdbc 可以在建立连接时,依照特定规则将客户端与主备集群的连接依次建立在 URL 中配置的各个节点上,以此实现连接的负载均衡。默认值为false,此时 jdbc 始终与 URL 中配置的同一个满足建连条件的节点建立连接。连接主备集群时,使用此参数需要保证业务中没有写操作,或者与 targetServerType=slave 搭配,限制客户端只连接备机。目前,jdbc 提供了 roundrobin、priority roundrobin、leastconn、shuffle 四种负载均衡模式,具体说明如下: |
reWriteBatchedInserts | Boolean | 批量导入时,该参数设置为 on,可将 N 条插入语句合并为一条:insert Integero TABLE_NAME values(values1, ..., valuesN), ..., (values1, ..., valuesN); 使用该参数时,需设置 batchMode=off。 |
replication | String | 指定启动报文的连接参数 replication 的值(true,database)。布尔值 true 告诉后端进入 walsender 模式,其中可以发出一小组复制命令而不是 SQL 语句。在 walsender 模式下只能使用简单查询协议。将数据库作为值传递指示 walsender 连接到 dbname 参数中指定的数据库,这将允许连接用于从该数据库进行逻辑复制。(后端>=9.4) |
TLSCiphersSupperted | String | 用于设置支持的 TLS 加密套件,默认为 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384。 |
xmlFactoryFactort | String | 指定用于进行实例化 Factory 以进行 xml 处理的 Factory 类。 |
bulkloadCtlFile | String | 指定 bulkload 控制文件的路径。 |
resultCaseMode | String | 用于控制返回字段名的大小写。该参数会设置当前连接的 result_case_mode 参数。 |
timeTextMode | Boolean | 指定是否使用 text 类型绑定时间参数,为了方式 JDBC 对时间的处理导致服务器收到的数据失真。默认值为 OFF。 |
exitCommit | Boolean | 指定是否在 session 关闭时提交事务,默认值为 OFF,表示不在会话关闭时提交事务。本功能仅在内部功能 Debug 调试需要,对实际开发、生产使用无相关意义。且不推荐用户使用该参数。 |
extraFloatDigits | Integer | 对 GUC 参数进行修改,为 session 级别,默认值为3,表示指定额外的浮动数字为3。 |
zzkk | String | 内部测试表现行为调试参数,不用于实际业务中,即用户不可使用。 |
oraBlobMode | Boolean | 针对 Blob 的新类型 oraBlob 进行相关逻辑改动。 |
userVexDBProductName | Boolean | 指定是否使用 VexDB 作为productName 的返回。 |
quoteReturningIdentifiers | Boolean | 指定是否引用返回列,默认值为 false,表示不引用。 |
loginWithHostname | Boolean | 指定是否在系统视图 v$session 中查询中带有操作系统用户名称和主机名称。默认值为 false,表示不在系统视图中添加上述信息。 |
enableStatementLoadBalance | Boolean | 是否开启语句级负载均衡,默认值为 false,表示不开启负载均衡。说明该参数仅在 JDBC V2.12 及以上版本支持。 |
writeDataSourceAddress | String | 指定集群内写节点的 IP 地址与端口号。仅支持配置一个 IP:Port 作为写节点。 |
使用方式
基础用法
应用程序通过执行SQL语句来操作数据库的数据(不用传递参数的语句),需要按以下步骤执行:
- 调用Connection的createStatement方法创建语句对象。
Connection conn = DriverManager.getConnection("url","user","password"); Statement stmt = conn.createStatement();
- 调用Statement的executeUpdate方法执行SQL语句。
int rc = stmt.executeUpdate("DROP TABLE IF EXISTS fruit_tbl;" + "CREATE TABLE fruit_tbl(fruit_id INTEGER, " + "fruit_name VARCHAR(32)," + "fruit_period INTEGER," + "fruit_email VARCHAR(64))");
- 数据库中收到的一次执行请求(不在事务块中),如果含有多条语句,将会被打包成一个事务,如果其中有一个语句失败,那么整个请求都将会被回滚。
- 事务块中不支持 vacuum 操作。
- 使用 Statement 执行多语句时应以
;
作为各语句间的分隔符。存储过程、函数、匿名块不支持多语句执行。 /
可用作创建单个存储过程、函数、匿名块的结束符。
- 关闭语句对象。
stmt.close();
VexDB-JDBC 主要类与接口
主要类或接口 | 包名 | 类或接口说明 |
---|---|---|
Driver 类 | com.vexdb.Driver | 当注册驱动的时候或配置软件以使用 VexDB JDBC 驱动的时候,应该使用这个类名。 |
DriverManager 类 | java.sql.DriverManager | 跟踪可用的驱动程序,在数据库与相应的驱动程序之间建立连接。应用服务器使用 JDBC 时,DriverManager 类管理连接的建立。需要为 DriverManager 配置 JDBC 驱动,最简单的方法就是使用实现了接口 java.sql.Driver 的类的 Class.forName() 方法。在 VexDB JDBC 驱动中,该类的名称为 com.vexdb.Driver。该方法可以在连接一个数据库时,使用一个外部配置文件来给驱动提供类名和驱动参数。 |
Connection 接口 | com.vexdb.PGConnection | 与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。 |
Statement 接口 | com.vexdb.PGStatement | 用于执行 SQL 语句并返回结果。 |
ResultSet 接口 | com.vexdb.PGResultSetMetaData | 存储执行 SQL 语句产生的结果集。 |
示例
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import com.vexdb.pgvector.PGvector;
public class pgVectorDemo {
static final String JDBC_DRIVER = "com.vexdb.Driver";
static final String DB_URL = "jdbc:vexdb://172.16.100.26:5432/postgres";
static final String USER = "vector_test";
static final String PASS = "Aa123456";
public static void main(String[] args) {
Connection conn = null;
try{
Class.forName(JDBC_DRIVER);
System.out.println("连接数据库...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
System.out.println(" 实例化 Statement 对象...");
Statement setupStmt = conn.createStatement();
setupStmt.executeUpdate("DROP TABLE IF EXISTS jdbc_items");
PGvector.addVectorType(conn);
/*
此处的 PGvector.addVectorType(conn)不可省略
如果缺少会导致 com.vexdb.util.PGobject cannot be cast to com.vexdb.pgvector.PGvector 的报错
*/
Statement createStmt = conn.createStatement();
createStmt.executeUpdate("CREATE TABLE jdbc_items (id bigserial PRIMARY KEY, embedding floatvector(3))");
PreparedStatement insertStmt = conn.prepareStatement("INSERT INTO jdbc_items (embedding) VALUES (?), (?), (?), (?)");
insertStmt.setObject(1, new PGvector(new float[] {1, 1, 1}));
insertStmt.setObject(2, new PGvector(new float[] {2, 2, 2}));
insertStmt.setObject(3, new PGvector(new float[] {1, 1, 2}));
insertStmt.setObject(4, null);
insertStmt.executeUpdate();
PreparedStatement neighborStmt = conn.prepareStatement("SELECT * FROM jdbc_items ORDER BY embedding <-> ? LIMIT 5");
neighborStmt.setObject(1, new PGvector(new float[] {1, 1, 1}));
ResultSet rs = neighborStmt.executeQuery();
List<Long> ids = new ArrayList<>();
List<PGvector> embeddings = new ArrayList<>();
while (rs.next()) {
ids.add(rs.getLong("id"));
embeddings.add((PGvector) rs.getObject("embedding"));
}
System.out.print("embeddings: " + embeddings.get(0));
System.out.print("embeddings: " + embeddings.get(1));
System.out.print("embeddings: " + embeddings.get(2));
Statement indexStmt = conn.createStatement();
indexStmt.executeUpdate("CREATE INDEX ON jdbc_items USING ivfflat (embedding floatvector_l2_ops) WITH (ivf_nlist = 100)");
setupStmt.close();
createStmt.close();
insertStmt.close();
neighborStmt.close();
indexStmt.close();
conn.close();
}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}