
Get Started with the JDBC Connector
This tutorial will walk you through how to get started accessing Kinetica with the JDBC Connector. In addition to explaining the core JDBC API best practices it will cover important functionality that is specific to Kinetica.
We will start by importing the tutorial project into eclipse and configuring the JDBC connection to use your local Kinetica instance. Next the tutorial will walk you through JUnit test cases that provide working examples that include:
- Creating a table
- Inserting and updating rows
- Querying for data
- Handling Kinetica specific datatypes
Finally, after you complete the tutorial the examples may be useful for troubleshooting issues encountered in the field.
Prerequisites
This tutorial assumes that you…
- Have a Java IDE. We will use Eclipse in the examples but others should work.
- Have access to a Kinetica 7.1 environment where you have permissions for create/insert/update of tables. If you don’t have this then you can get Kinetica Developer Edition which is free to try.
- Have familiarity with Java and SQL. When in doubt about Kinetica specific details you can review the Kinetica Online SQL Guide.
- Have access to the tutorial source code.
Setup
Project Import
The project we will be working with is located in Git and dependences are managed by Maven. In Eclipse select File->Import… Then choose Check out Maven Projects from SCM.
Click Next and enter the Git URL for the Project Repository. (e.g. https://chadjk@bitbucket.org/gisfederal/kinetica-jdbc-demo.git)
After the import is complete you should see the fully compiled project in the Package Explorer.
JDBC Connector Dependency
The project will retrieve the Kinetica JDBC Library from the Kinetica Maven Repository. For this to happen the repository must be defined in the pom.xml.
Below is an example of the Maven dependency. You should check the repository for the latest version.
Additional JDBC Connector resources resources are available:
- See the Kinetica JDBC Connector Guide.
- As an alternative you can download the JAR from the Kinetica Client JDBC Repository.
Running the Examples
The example code is provided as JUnit tests. Before you can run them you must configure the connection.
Open the file /kinetica-jdbc-demo/src/main/java/com/kinetica/tutorial/jdbc/TestConstants.java and edit the below parameters with your own connection parameters.
public static final String URL = "jdbc:kinetica://hostname:9191";
public static final String USER = "admin";
public static final String PASS = "???";
Open the file /kinetica-jdbc-demo/src/main/java/com/kinetica/tutorial/jdbc/TestJdbc.java, right click on the createTable() test case, and select Run As -> JUnit Test.
In the log you should see the below results indicating that a table TEST.jdbc_test was successfully created.
Example Table
The test case createTable() created a schema and table that will be used by the examples in the following sections. The full DDL is shown below.
We will take a close look at the column definitions and understand how they are represented in Kinetica. More information is available in Data Definition (DDL).
Column Name | SQL Type | Java Type | Description |
id_str | VARCHAR(16, dict) | String | 16 byte string using dictionary compression. |
test_long | BIGINT | Long | 8 byte integer |
test_int | INTEGER | Integer | 4 type integer |
test_date | DATE | LocalDate | 4 byte date with accuracy of day |
test_timestamp | TIMESTAMP | Instant | 8 byte type with accuracy of milliseconds |
test_datetime | DATETIME | Instant | 8 byte type with accuracy of milliseconds |
The id_str column is also the primary key for the table so duplicate entries will be prevented.
The datatypes TIMESTAMP and DATETIME appear identical for JDBC operations. The key difference is that TIMESTAMP is passed to the application as an integer while DATETIME is passed as a formatted string. This means that TIMESTAMP can reduce CPU and network load but it leaves formatting up to the application.
The JDBC API
Connecting
When a JUnit test case is started it will first invoke com.kinetica.tutorial.jdbc.TestJdbc.setUp() which contains the code to establish the JDBC connection. The resulting connection object is saved in this.dbc.
First the Kinetica driver must be registered with the JDBC Framework. We load the driver static class which will force it to register itself. Many other examples will show this driver being dynamically loaded.
Next we create a container for the parameters. The TestConstants object contains the connection parameters from the previous section.
Finally we pass the URL and properties to create the Connection.
Don’t forget to close the connection after the operations are complete.
Inserting rows
The PreparedStatement class is used for executing DML statements like INSERT, UPDATE, and DELETE. As an alternative you could use Statement but it is not parameterized and is at risk of SQL injection attacks.
The insert test is performed by TestJdbc.testInsert(). There are multiple API’s that can be used to insert rows; however, it is a best practice to use PreparedStatement because it is safe from SQL injection attacks.
We first define a parameterized SQL template. The hint KI_HINT_UPDATE_ON_EXISTING_PK indicates that if the row being inserted is already in the PK then it will be updated. Without this hint the duplicate row would be ignored.
We open a try block to create the PreparedStatement. The try block will guarantee that the statement is automatically closed. If you don’t use the try block then you need to remember to call PreparedStatement.close() in all cases or you could leak resources.
You populate the row by calling the various set() functions in PreparedStatement. The index relates to the position of the “?” in the statement where the index starts with 1.
To insert a date or timestamp you will need to convert it to java.sql.Timestamp or java.sql.Date which are specialized JDBC classes. In the example below we use setTimestamp() for the TIMESTAMP and DATETIME DDL types.
Finally we call executeUpdate() to insert a single row.
Updating Rows
The UPDATE operation works similar to INSERT except that we provide a different statement and set of parameters.
There are 3 parameters in this statement where the last one indicates the key of the row to update.
Note: Since this table has a PK we could use the KI_HINT_UPDATE_ON_EXISTING_PK hint along with insert as a faster alternative.
Bulk Operations
Executing statements one at a time is not very efficient and so PreparedStatement provides a means of grouping operations together for bulk execution. You can run this example with TestJdbc.testInsertBatch().
First use try to create a PreparedStatement. In this example we re-use the INSERT statement from the earlier example.
Next we loop through each row and call addBatch(). This operation will prepare the row for the bulk insert.
Finally we call executeBatch() to insert the rows. The Kinetica driver, by design, returns only a total of the rows inserted. This could be different then the number of rows you added if some of them failed to insert because of constraint violations so you should always check.
To find out why some rows failed you can check the warnings.
SQLWarning warnings = pstmt.getWarnings();
Executing Queries
This example will show how to perform a query using java.sql.PreparedStatement.executeQuery(). We could use java.sql.Statement.executeQuery(String) but parameters in the statement could be at risk for SQL injection. You can run this example with TestJdbc.testQuery().
First we define a parameterized statement.
We create the PreparedStatement and set the parameter for the where predicate.
Next we call executeQuery() to create the result set inside the try block. If we did not use the try block then we would need to call ResultSet.close().
Finally we loop through the results and call the appropriate get() function for the column index.
Note that the test_timestamp and test_datetime columns can both be fetched with getTimestamp() or getString().
Troubleshooting
When opening the connection you can optionally enable debug logging. We enable this by specifying the log level and path in the connection properties.
This will log results to the file ./logs/KineticaJDBC.log. You should see output that looks something like the below example.
Conclusion
We appreciate the time you have taken to complete this tutorial. The below links provide additional resources exploring Kinetica and JDBC functionality.
Kinetica Resources:
- Kinetica JDBC Driver Download
- Kinetica SQL Guide
Core JDBC Resources:
Making Sense of Sensor Data
