1. Overview
1.概述
In this tutorial, we’ll discuss Java’s support for HarperDB, a high-performing flexible NoSQL database with the power of SQL. No doubt, the standard Java database connectivity helps integrate it with a wide range of leading BI, reporting, ETL Tools, and custom applications. It also provides REST APIs for performing DB administration and operations.
在本教程中,我们将讨论 Java 对HarperDB的支持,这是一种具有 SQL 功能的高性能灵活 NoSQL 数据库。毫无疑问,标准的 Java 数据库连接性有助于将其与各种领先的 BI、报表、ETL 工具和自定义应用程序集成。它还提供了REST API,用于执行数据库管理和操作。
However, JDBC streamlines and accelerates the adoption of HarperDB within applications. It might simplify and expedite the process significantly.
然而,JDBC 简化并加快了 HarperDB 在应用程序中的应用。它可以大大简化和加快这一过程。
For this tutorial, we’ll use the Java Test Container library. This would enable us to run a HarperDB Docker container and showcase a live integration.
在本教程中,我们将使用Java 测试容器库。这将使我们能够运行 HarperDB Docker 容器并展示实时集成。
Let’s explore the extent of JDBC support available for HarperDB through some examples.
让我们通过一些示例来探索 HarperDB 可用的 JDBC 支持范围。
2. JDBC Library
2.JDBC 库
HarperDB ships with a JDBC library, which we’ll import in our pom.xml file:
HarperDB 随附一个 JDBC 库,我们将在 pom.xml 文件中导入该库:
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>java-harperdb</artifactId>
<version>4.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/cdata.jdbc.harperdb.jar</systemPath>
</dependency>
Since it’s unavailable on a public Maven repository, we must import it from our local directory or a private Maven repository.
由于公共 Maven 资源库中没有它,我们必须从本地目录或私有 Maven 资源库中导入。
3. Create JDBC Connection
3.创建 JDBC 连接
Before we can start executing the SQL statements in the Harper DB, we’ll explore how to acquire the java.sql.Connection object.
在开始执行 Harper DB 中的 SQL 语句之前,我们将探讨如何获取 java.sql.Connection 对象。
Let’s start with the first option:
让我们从第一个方案开始:
@Test
void whenConnectionInfoInURL_thenConnectSuccess() {
assertDoesNotThrow(() -> {
final String JDBC_URL = "jdbc:harperdb:Server=127.0.0.1:" + port + ";User=admin;Password=password;";
try (Connection connection = DriverManager.getConnection(JDBC_URL)) {
connection.createStatement().executeQuery("select 1");
logger.info("Connection Successful");
}
});
}
There isn’t much difference compared to getting a connection for relational databases, except for the prefix jdbc:harperdb: in the JDBC URL. Usually, the password should always be encrypted and decrypted before being passed to the URL.
除了 JDBC URL 中的前缀jdbc:harperdb:外,与获取关系数据库的连接没有太大区别。通常情况下,密码在传递到 URL 之前应始终经过加密和解密。
Moving on, let’s take a look at the second option:
接下来,让我们看看第二种方案:
@Test
void whenConnectionInfoInProperties_thenConnectSuccess() {
assertDoesNotThrow(() -> {
Properties prop = new Properties();
prop.setProperty("Server", "127.0.0.1:" + port);
prop.setProperty("User", "admin");
prop.setProperty("Password", "password");
try (Connection connection = DriverManager.getConnection("jdbc:harperdb:", prop)) {
connection.createStatement().executeQuery("select 1");
logger.info("Connection Successful");
}
});
}
In contrast to the earlier option, we used the Properties object to pass the connectivity details to DriveManager.
与之前的选项不同,我们使用 Properties 对象将连接详情传递给 DriveManager 。
Applications often use connection pools for optimal performance. Hence, it’s reasonable to expect that HarperDB’s JDBC driver also incorporates the same:
应用程序通常使用连接池来获得最佳性能。因此,我们有理由期待 HarperDB 的 JDBC 驱动程序也采用同样的方法:
@Test
void whenConnectionPooling_thenConnectSuccess() {
assertDoesNotThrow(() -> {
HarperDBConnectionPoolDataSource harperdbPoolDataSource = new HarperDBConnectionPoolDataSource();
final String JDBC_URL = "jdbc:harperdb:UseConnectionPooling=true;PoolMaxSize=2;Server=127.0.0.1:" + port
+ ";User=admin;Password=password;";
harperdbPoolDataSource.setURL(JDBC_URL);
try(Connection connection = harperdbPoolDataSource.getPooledConnection().getConnection()) {
connection.createStatement().executeQuery("select 1");
logger.info("Connection Successful");
}
});
}
To enable connection pooling, we used the property UseConnectionPooling=true. Also, we had to use the driver class HarperDBConnectionPoolDataSource to get the connection pool.
为启用连接池,我们使用了属性 UseConnectionPooling=true。此外,我们还必须使用驱动程序类 HarperDBConnectionPoolDataSource 来获取连接池。
Additionally, other connection properties can be used for more options.
此外,还可以使用其他连接属性来获得更多选项。
4. Create Schema and Tables
4.创建模式和表
HaperDB provides RESTful database operation APIs for configuring and administering the database. It also has APIs for creating database objects and performing SQL CRUD operations on them.
HaperDB 提供 RESTful 数据库操作 API,用于配置和管理数据库。它还有用于创建数据库对象和对其执行 SQL CRUD 操作的 API。
However, DDL statements like Create Table, Create Schema, etc. aren’t supported. However, HarperDB provides stored procedures for creating schemas and tables:
但是,不支持 Create Table(创建表)、Create Schema(创建模式) 等 DDL 语句。不过,HarperDB 提供了存储过程用于创建模式和表:
@Test
void whenExecuteStoredToCreateTable_thenSuccess() throws SQLException {
final String CREATE_TABLE_PROC = "CreateTable";
try (Connection connection = getConnection()) {
CallableStatement callableStatement = connection.prepareCall(CREATE_TABLE_PROC);
callableStatement.setString("SchemaName", "Prod");
callableStatement.setString("TableName", "Subject");
callableStatement.setString("PrimaryKey", "id");
Boolean result = callableStatement.execute();
ResultSet resultSet = callableStatement.getResultSet();
while (resultSet.next()) {
String tableCreated = resultSet.getString("Success");
assertEquals("true", tableCreated);
}
}
}
The CallableStatement executes the CreateTable stored procedure and creates the table Subject in the Prod schema. The procedure takes SchemaName, TableName, and PrimaryKey as the input parameters. Interestingly we didn’t create the schema explicitly. The schema gets created if it’s not present in the database.
CallableStatement执行存储过程 CreateTable,并在 Prod 模式中创建表 Subject 。存储过程将 SchemaName, TableName, 和 PrimaryKey 作为输入参数。有趣的是,我们并没有明确创建模式。如果数据库中没有模式,就会创建模式。
Similarly, other stored procedures like CreateHarperSchema, DropSchema, DropTable, etc. can be invoked by the CallableStatement.
同样,CallableStatement 可以调用其他存储过程,如 CreateHarperSchema、DropSchema、DropTable 等。
5. CRUD Support
5.CRUD 支持
The HarperDB JDBC Driver supports the CRUD operations. We can create, query, update, and delete records from tables using java.sql.Statement and java.sql.PreparedSatement.
HarperDB JDBC 驱动程序支持 CRUD 操作。我们可以使用 java.sql.Statement 和 java.sql.PreparedSatement 从表中创建、查询、更新和删除记录。
5.1. DB Model
5.1 DB 模型
Before we move on to the next sections, let’s set up some data for executing SQL statements. Let’s assume a database schema called Demo that has three tables:
在进入下一节之前,让我们设置一些用于执行 SQL 语句的数据。我们假设一个名为 Demo 的数据库模式有三个表:
Subject and Teacher are two master tables. The table Teacher_Details has the details of the subjects taught by teachers. Unexpectedly, there are no foreign key constraints on the fields teacher_id and subject_id because there is no support for it in HarperDB.
Subject 和 Teacher 是两个主表。表 Teacher_Details 包含教师所教科目的详细信息。出乎意料的是,在 teacher_id 和 subject_id 字段上没有外键约束,因为 HarperDB 不支持外键约束。
Let’s take a look at the data in the Subject table:
让我们来看看 Subject 表中的数据:
[
{"id":1, "name":"English"},
{"id":2, "name":"Maths"},
{"id":3, "name":"Science"}
]
Similarly, let’s take a look at the data in the Teacher table:
同样,让我们看看 Teacher 表中的数据:
[
{"id":1, "name":"James Cameron", "joining_date":"04-05-2000"},
{"id":2, "name":"Joe Biden", "joining_date":"20-10-2005"},
{"id":3, "name":"Jessie Williams", "joining_date":"04-06-1997"},
{"id":4, "name":"Robin Williams", "joining_date":"01-01-2020"},
{"id":5, "name":"Eric Johnson", "joining_date":"04-05-2022"},
{"id":6, "name":"Raghu Yadav", "joining_date":"02-02-1999"}
]
Now, let’s see the records in the Teacher_Details table:
现在,让我们看看 Teacher_Details 表中的记录:
[
{"id":1, "teacher_id":1, "subject_id":1},
{"id":2, "teacher_id":1, "subject_id":2},
{"id":3, "teacher_id":2, "subject_id":3 },
{"id":4, "teacher_id":3, "subject_id":1},
{"id":5, "teacher_id":3, "subject_id":3},
{"id":6, "teacher_id":4, "subject_id":2},
{"id":7, "teacher_id":5, "subject_id":3},
{"id":8, "teacher_id":6, "subject_id":1},
{"id":9, "teacher_id":6, "subject_id":2},
{"id":15, "teacher_id":6, "subject_id":3}
]
Notably, the column id in all the tables is the primary key.
值得注意的是,所有表中的 id 列都是主键。
5.2. Create Records With Insert
5.2.使用 Innsert 创建记录
Let’s introduce some more subjects by creating some records in the Subject table:
让我们通过在 Subject 表中创建一些记录来介绍更多主题:
@Test
void givenStatement_whenInsertRecord_thenSuccess() throws SQLException {
final String INSERT_SQL = "insert into Demo.Subject(id, name) values "
+ "(4, 'Social Studies'),"
+ "(5, 'Geography')";
try (Connection connection = getConnection()) {
Statement statement = connection.createStatement();
assertDoesNotThrow(() -> statement.execute(INSERT_SQL));
assertEquals(2, statement.getUpdateCount());
}
}
We used java.sql.Statement to insert two records into the Subject table.
我们使用 java.sql.Statement 向 Subject 表插入两条记录。
Let’s implement a better version with the help of the java.sql.PrepareStatement by considering the Teacher table:
让我们借助 java.sql.PrepareStatement 实现一个更好的版本,并考虑 Teacher 表:
@Test
void givenPrepareStatement_whenAddToBatch_thenSuccess() throws SQLException {
final String INSERT_SQL = "insert into Demo.Teacher(id, name, joining_date) values"
+ "(?, ?, ?)";
try (Connection connection = getConnection()) {
PreparedStatement preparedStatement = connection.prepareStatement(INSERT_SQL);
preparedStatement.setInt(1, 7);
preparedStatement.setString(2, "Bret Lee");
preparedStatement.setString(3, "07-08-2002");
preparedStatement.addBatch();
preparedStatement.setInt(1, 8);
preparedStatement.setString(2, "Sarah Glimmer");
preparedStatement.setString(3, "07-08-1997");
preparedStatement.addBatch();
int[] recordsInserted = preparedStatement.executeBatch();
assertEquals(2, Arrays.stream(recordsInserted).sum());
}
}
So, we parameterized the insert statement and executed them in batches with the methods addBatch() and executeBatch(). Batch execution is crucial for processing large volumes of records. Hence its support in HarperDB’s JDBC driver is immensely valuable.
因此,我们将 insert 语句参数化,并使用方法 addBatch() 和 executeBatch() 分批执行。批处理对于处理大量记录至关重要。因此,HarperDB 的 JDBC 驱动程序对它的支持非常有价值。
5.3. Create Records With Insert Into Select
5.3.使用 Innsert Into Select 创建记录
HarperDB JDBC driver also provides the feature of creating temporary tables at run time. This temporary table can later be used for inserting into a final target table with a single insert into select statement. Similar to batch execution this also helps reduce the number of calls to the database.
HarperDB JDBC 驱动程序还提供了在运行时创建临时表的功能。该临时表随后可用于通过单个 insert into select 语句插入到最终目标表中。与批量执行类似,这也有助于减少对数据库的调用次数。
Let’s see this feature in action:
让我们看看这一功能的实际效果:
@Test
void givenTempTable_whenInsertIntoSelectTempTable_thenSuccess() throws SQLException {
try (Connection connection = getConnection()) {
Statement statement = connection.createStatement();
assertDoesNotThrow(() -> {
statement.execute("insert into Teacher#TEMP(id, name, joining_date) "
+ "values('12', 'David Flinch', '04-04-2014')");
statement.execute("insert into Teacher#TEMP(id, name, joining_date) "
+ "values('13', 'Stephen Hawkins', '04-07-2017')");
statement.execute("insert into Teacher#TEMP(id, name, joining_date) "
+ "values('14', 'Albert Einstein', '12-08-2020')");
statement.execute("insert into Teacher#TEMP(id, name, joining_date) "
+ "values('15', 'Leo Tolstoy', '20-08-2022')");
});
assertDoesNotThrow(() -> statement.execute("insert into Demo.Teacher(id, name, joining_date) "
+ "select id, name, joining_date from Teacher#TEMP"));
ResultSet resultSet = statement.executeQuery("select count(id) as rows from Demo.Teacher where id in"
+ " (12, 13, 14, 15)");
resultSet.next();
int totalRows = resultSet.getInt("rows");
assertEquals(4, totalRows);
}
}
All temp tables should have the format [table name]#TEMP as in Teacher#TEMP. It gets created as soon as we execute the insert statement. Four records were inserted into the temporary table Teacher#TEMP. Then with a single insert into select statement all the records got inserted into the target Teacher table.
所有临时表的格式应为 [表名]#TEMP,如 教师#TEMP。只要我们执行 insert 语句,就会创建临时表。在临时表 Teacher#TEMP 中插入了四条记录。然后,通过一条 insert into select 语句,所有记录都被插入到目标表 Teacher 中。
5.4. Read Records From Tables
5.4.从表中读取记录
Let’s begin by querying the Subject table with the help of java.sql.Statement:
首先,让我们借助 java.sql.Statement 查询 Subject 表:
@Test
void givenStatement_whenFetchRecord_thenSuccess() throws SQLException {
final String SQL_QUERY = "select id, name from Demo.Subject where name = 'Maths'";
try (Connection connection = getConnection()) {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(SQL_QUERY);
while (resultSet.next()) {
Integer id = resultSet.getInt("id");
String name = resultSet.getString("name");
assertNotNull(id);
logger.info("Subject id:" + id + " Subject Name:" + name);
}
}
}
The executeQuery() method of the java.sql.Statement executes successfully and fetches the records.
java.sql.Statement 的 executeQuery() 方法成功执行并获取记录。
Let’s see if the driver supports java.sql.PrepareStatement. This time let’s execute a query with a join condition to make it a little bit more exciting and complex:
让我们看看驱动程序是否支持 java.sql.PrepareStatement。这一次,让我们执行一个带有连接条件的查询,让它变得更刺激、更复杂一些:
@Test
void givenPreparedStatement_whenExecuteJoinQuery_thenSuccess() throws SQLException {
final String JOIN_QUERY = "SELECT t.name as teacher_name, t.joining_date as joining_date, s.name as subject_name "
+ "from Demo.Teacher_Details AS td "
+ "INNER JOIN Demo.Teacher AS t ON t.id = td.teacher_id "
+ "INNER JOIN Demo.Subject AS s on s.id = td.subject_id "
+ "where t.name = ?";
try (Connection connection = getConnection()) {
PreparedStatement preparedStatement = connection.prepareStatement(JOIN_QUERY);
preparedStatement.setString(1, "Eric Johnson");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
String teacherName = resultSet.getString("teacher_name");
String subjectName = resultSet.getString("subject_name");
String joiningDate = resultSet.getString("joining_date");
assertEquals("Eric Johnson", teacherName);
assertEquals("Maths", subjectName);
}
}
}
We not only executed a parameterized query but also discovered that HarperDB can perform join queries on unstructured data.
我们不仅执行了参数化查询,还发现 HarperDB 可以对非结构化数据执行连接查询。
5.5. Read Records From User-Defined Views
5.5.从用户自定义视图读取记录
The HarperDB driver has the feature for creating user-defined views. These are virtual views that can be used in scenarios where we don’t have access to the table queries, i.e., when using the driver from a tool.
HarperDB 驱动程序具有创建 用户自定义视图的功能。这些是虚拟视图,可用于我们无法访问表查询的场景,即从工具中使用驱动程序时。
Let’s define a view in a file UserDefinedViews.json:
让我们在文件 UserDefinedViews.json 中定义一个视图:</em
{
"View_Teacher_Details": {
"query": "SELECT t.name as teacher_name, t.joining_date as joining_date, s.name as subject_name from Demo.Teacher_Details AS td
INNER JOIN Demo.Teacher AS t ON t.id = td.teacher_id INNER JOIN Demo.Subject AS s on s.id = td.subject_id"
}
}
The query gets the details of the teacher by joining all the tables. The default schema of the view is UserViews.
该查询通过连接所有表来获取教师的详细信息。视图的默认模式是 用户视图。
The driver looks for the UserDefinedViews.json in the directory defined by the connection property Location. Let’s see how this works:
驱动程序会在连接属性 Location 所定义的目录中查找 UserDefinedViews.json. 让我们看看它是如何工作的:
@Test
void givenUserDefinedView_whenQueryView_thenSuccess() throws SQLException {
URL url = ClassLoader.getSystemClassLoader().getResource("UserDefinedViews.json");
String folderPath = url.getPath().substring(0, url.getPath().lastIndexOf('/'));
try(Connection connection = getConnection(Map.of("Location", folderPath))) {
PreparedStatement preparedStatement = connection.prepareStatement("select teacher_name,subject_name"
+ " from UserViews.View_Teacher_Details where subject_name = ?");
preparedStatement.setString(1, "Science");
ResultSet resultSet = preparedStatement.executeQuery();
while(resultSet.next()) {
assertEquals("Science", resultSet.getString("subject_name"));
}
}
}
To create the database connection, the program passes on the folder path of the file UserDefinedViews.json to the method getConnection(). After this, the driver executes the query on the view View_Teacher_Details and gets the details of all the teachers who teach Science.
为创建数据库连接,程序将文件 UserDefinedViews.json 的文件夹路径传递给方法 getConnection() 。然后,驱动程序在视图 View_Teacher_Details 上执行查询,并获取所有教授 Science 的教师的详细信息。
5.6. Save and Read Records From Cache
5.6.从缓存中保存和读取记录
Applications prefer caching frequently used and accessed data to improve performance. HaperDB driver enables caching data in locations such as on a local disk or a database.
应用程序喜欢缓存经常使用和访问的数据,以提高性能。HaperDB 驱动程序可在本地磁盘或数据库等位置缓存数据。
For our example, we’ll use an embedded Derby database as the cache in our Java application. But there is provision for selecting other databases for caching as well.
在我们的示例中,我们将使用嵌入式 Derby 数据库作为 Java 应用程序中的缓存。但也可以选择 其他数据库作为缓存。
Let’s explore more on this:
让我们进一步探讨这个问题:
@Test
void givenAutoCache_whenQuery_thenSuccess() throws SQLException {
URL url = ClassLoader.getSystemClassLoader().getResource("test.db");
String folderPath = url.getPath().substring(0, url.getPath().lastIndexOf('/'));
logger.info("Cache Location:" + folderPath);
try(Connection connection = getConnection(Map.of("AutoCache", "true", "CacheLocation", folderPath))) {
PreparedStatement preparedStatement = connection.prepareStatement("select id, name from Demo.Subject");
ResultSet resultSet = preparedStatement.executeQuery();
while(resultSet.next()) {
logger.info("Subject Name:" + resultSet.getString("name"));
}
}
}
We’ve used two connection properties AutoCache and CacheLocation. AutoCache=true means all queries to the table are going to be cached to the location specified in the property CacheLocation. However, the driver provides explicit caching capability as well using the CACHE statements.
我们使用了两个连接属性 AutoCache 和 CacheLocation 。AutoCache=true 意味着对表的所有查询都将缓存到 CacheLocation 属性中指定的位置。不过,驱动程序还使用 CACHE 语句提供了显式缓存功能。
5.7. Update Records
5.7.更新记录
Let’s see an example of updating the subjects taught by the teachers with java.sql.Statement:
让我们来看一个使用 java.sql.Statement 更新教师所教科目的示例:
@Test
void givenStatement_whenUpdateRecord_thenSuccess() throws SQLException {
final String UPDATE_SQL = "update Demo.Teacher_Details set subject_id = 2 "
+ "where teacher_id in (2, 5)";
final String UPDATE_SQL_WITH_SUB_QUERY = "update Demo.Teacher_Details "
+ "set subject_id = (select id from Demo.Subject where name = 'Maths') "
+ "where teacher_id in (select id from Demo.Teacher where name in ('Joe Biden', 'Eric Johnson'))";
try (Connection connection = getConnection()) {
Statement statement = connection.createStatement();
assertDoesNotThrow(() -> statement.execute(UPDATE_SQL));
assertEquals(2, statement.getUpdateCount());
}
try (Connection connection = getConnection()) {
assertThrows(SQLException.class, () -> connection.createStatement().execute(UPDATE_SQL_WITH_SUB_QUERY));
}
}
The first update statement successfully executes when we directly use the id of the teacher and subject and don’t look up the values from the other tables. However, the second update fails when we try to look up the id values from the Teacher and Subject tables. This happens because currently, HarperDB doesn’t support subqueries.
当我们直接使用教师和学科的 id 而不从其他表中查找值时,第一条 update 语句会成功执行。但是,当我们尝试从 Teacher 表和 Subject 表中查找 id 值时,第二次更新失败。出现这种情况是因为 HarperDB 目前不支持子查询。
Let’s use java.sql.PreparedStatement to update the subjects taught by a teacher:
让我们使用 java.sql.PreparedStatement 来更新教师教授的科目:
@Test
void givenPreparedStatement_whenUpdateRecord_thenSuccess() throws SQLException {
final String UPDATE_SQL = "update Demo.Teacher_Details set subject_id = ? "
+ "where teacher_id in (?, ?)";
try (Connection connection = getConnection()) {
PreparedStatement preparedStatement = connection.prepareStatement(UPDATE_SQL);
preparedStatement.setInt(1, 1);
//following is not supported by the HarperDB driver
//Integer[] teacherIds = {4, 5};
//Array teacherIdArray = connection.createArrayOf(Integer.class.getTypeName(), teacherIds);
preparedStatement.setInt(2, 4);
preparedStatement.setInt(3, 5);
assertDoesNotThrow(() -> preparedStatement.execute());
assertEquals(2, preparedStatement.getUpdateCount());
}
}
Unfortunately, the HarperDB JDBC driver doesn’t support creating a java.sql.Array object and hence we cannot pass an array of teacher ids as a parameter in the in clause. That is why we have to call setInt() multiple times to set the teacher ids. This is a drawback and can cause lots of inconvenience.
遗憾的是,HarperDB JDBC 驱动程序不支持创建 java.sql.Array 对象,因此我们无法在 in clause 中将教师 ids 数组作为参数传递。这就是为什么我们必须多次调用 setInt() 来设置教师 ids 的原因。这是一个缺点,会带来很多不便。
5.8. Delete Records
5.8.删除记录
Let’s execute a delete statement on the table Teacher_Details:
让我们在表 Teacher_Details 上执行 delete 语句:
@Test
void givenStatement_whenDeleteRecord_thenSuccess() throws SQLException {
final String DELETE_SQL = "delete from Demo.Teacher_Details where teacher_id = 6 and subject_id = 3";
try (Connection connection = getConnection()) {
Statement statement = connection.createStatement();
assertDoesNotThrow(() -> statement.execute(DELETE_SQL));
assertEquals(1, statement.getUpdateCount());
}
}
java.sql.Statement helped delete the record successfully.
java.sql.Statement 帮助成功删除了记录。
Moving on, let’s try using java.sql.PreparedStatement:
接下来,让我们尝试使用 java.sql.PreparedStatement :
@Test
void givenPreparedStatement_whenDeleteRecord_thenSuccess() throws SQLException {
final String DELETE_SQL = "delete from Demo.Teacher_Details where teacher_id = ? and subject_id = ?";
try (Connection connection = getConnection()) {
PreparedStatement preparedStatement = connection.prepareStatement(DELETE_SQL);
preparedStatement.setInt(1, 6);
preparedStatement.setInt(2, 2);
assertDoesNotThrow(() -> preparedStatement.execute());
assertEquals(1, preparedStatement.getUpdateCount());
}
}
We could parameterize and execute the delete statement successfully.
我们可以成功参数化并执行 delete 语句。
6. Conclusion
6.结论
In this article, we learned about the JDBC support in HarperDB. HarperDB is a NoSQL database but its JDBC driver enables Java applications to execute SQL statements. There are a few SQL features that HarperDB doesn’t yet support.
在本文中,我们了解了 HarperDB 中的 JDBC 支持。HarperDB 是一个 NoSQL 数据库,但其 JDBC 驱动程序可让 Java 应用程序执行 SQL 语句。HarperDB 还不支持一些 SQL 功能。
Furthermore, the driver is also not one hundred percent compliant with JDBC protocol. But it compensates it with some of its features like user-defined views, temporary tables, caching, etc.
此外,该驱动程序也不完全符合 JDBC 协议。但它的一些功能(如用户定义视图、临时表、缓存等)弥补了这一点。
As usual, the codes used for the examples in this article are available over on GitHub.
与往常一样,本文示例中使用的代码可在 GitHub 上获取。