Java

This guide describes how to create a SerenDB project and connect to it from a Java application using Java Database Connectivity (JDBC), the standard API for interacting with relational databases in Java.

You will learn how to set up a project, connect to your database, and perform basic create, read, update, and delete (CRUD) operations.

Prerequisites

Create a SerenDB project

If you do not have one already, create a SerenDB project.

  1. Navigate to the Projects page in the SerenDB Console.

  2. Click New Project.

  3. Specify your project settings and click Create Project.

Your project is created with a ready-to-use database named neondb. In the following steps, you will connect to this database from your Java application.

Create a Java project

Create a project using the Maven archetype:generate command. This sets up a standard Java project structure.

  1. Run the following command in your terminal to generate a new Maven project. This command creates a simple Java project with the maven-archetype-quickstart archetype.

    mvn archetype:generate \
        -DarchetypeGroupId=org.apache.maven.archetypes \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DarchetypeVersion=1.5 \
        -DgroupId=com.neon.quickstart \
        -DartifactId=neon-java-jdbc \
        -DinteractiveMode=false
  2. Change into the newly created project directory.

    cd neon-java-jdbc

    Open this directory in your preferred code editor (e.g., VS Code, IntelliJ IDEA).

  3. Add the postgresql driver and dotenv-java libraries as dependencies in your pom.xml file. There may be other dependencies already present (e.g, junit), so ensure you add these within the <dependencies> section.

    <dependencies>
      <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.7.3</version>
      </dependency>
      <dependency>
        <groupId>io.github.cdimascio</groupId>
        <artifactId>dotenv-java</artifactId>
        <version>3.2.0</version>
      </dependency>
    </dependencies>

    Make sure to add this to the `` section. A common mistake is adding it to ``, which only declares a version but doesn't actually include the library in your build.

    Save the file.

  4. Compile the project to download the dependencies.

    mvn clean compile

    This command compiles your Java code and downloads the required dependencies specified in pom.xml.

Store your SerenDB connection string

Create a file named .env in your project's root directory. This file will securely store your database connection string.

  1. In the SerenDB Console, select your project on the Dashboard.

  2. Click Connect on your Project Dashboard to open the Connect to your database modal.

  3. Select Java as your programming language. Connection modal

  4. Copy the connection string, which includes your password.

  5. Create a file named .env in your project's root directory and add the connection string to it as shown below:

    DATABASE_URL="jdbc:postgresql://[seren_hostname]/[dbname]?user=[user]&password=[password]&sslmode=require&channelBinding=require"

    Replace [user], [password], [seren_hostname], and [dbname] with your actual database credentials.

Examples

This section provides code examples for performing CRUD operations. The examples should be placed inside src/main/java/com/neon/quickstart/.

Create a table and insert data

Create a file named CreateTable.java. This class connects to your database, creates a table, and inserts data.

package com.neon.quickstart;

import io.github.cdimascio.dotenv.Dotenv;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;

public class CreateTable {

    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();
        String connString = dotenv.get("DATABASE_URL");

        try (Connection conn = DriverManager.getConnection(connString)) {
            System.out.println("Connection established");

            try (Statement stmt = conn.createStatement()) {
                // Drop the table if it already exists
                stmt.execute("DROP TABLE IF EXISTS books;");
                System.out.println("Finished dropping table (if it existed).");

                // Create a new table
                stmt.execute("""
                    CREATE TABLE books (
                        id SERIAL PRIMARY KEY,
                        title VARCHAR(255) NOT NULL,
                        author VARCHAR(255),
                        publication_year INT,
                        in_stock BOOLEAN DEFAULT TRUE
                    );
                """);
                System.out.println("Finished creating table.");

                // Insert a single book record
                String insertOneSql = "INSERT INTO books (title, author, publication_year, in_stock) VALUES (?, ?, ?, ?);";
                try (PreparedStatement pstmt = conn.prepareStatement(insertOneSql)) {
                    pstmt.setString(1, "The Catcher in the Rye");
                    pstmt.setString(2, "J.D. Salinger");
                    pstmt.setInt(3, 1951);
                    pstmt.setBoolean(4, true);
                    pstmt.executeUpdate();
                    System.out.println("Inserted a single book.");
                }

                // Insert multiple books
                String insertManySql = "INSERT INTO books (title, author, publication_year, in_stock) VALUES (?, ?, ?, ?);";
                try (PreparedStatement pstmt = conn.prepareStatement(insertManySql)) {
                    Object[][] booksToInsert = {
                        {"The Hobbit", "J.R.R. Tolkien", 1937, true},
                        {"1984", "George Orwell", 1949, true},
                        {"Dune", "Frank Herbert", 1965, false}
                    };

                    for (Object[] book : booksToInsert) {
                        pstmt.setString(1, (String) book[0]);
                        pstmt.setString(2, (String) book[1]);
                        pstmt.setInt(3, (Integer) book[2]);
                        pstmt.setBoolean(4, (Boolean) book[3]);
                        pstmt.addBatch();
                    }
                    pstmt.executeBatch();
                    System.out.println("Inserted 3 rows of data.");
                }
            }
        } catch (Exception e) {
            System.out.println("Connection failed.");
            e.printStackTrace();
        }
    }
}

The above code does the following:

  • Connects to the SerenDB database using the connection string from the .env file.

  • Drops the books table if it already exists.

  • Creates a new books table with columns for id, title, author, publication_year, and in_stock.

  • Inserts a single book record.

  • Inserts multiple book records in a batch operation.

Run the code to create the table and insert the data using the following command:

mvn exec:java -Dexec.mainClass="com.neon.quickstart.CreateTable"

When the code runs successfully, it produces the following output:

Connection established
Finished dropping table (if it existed).
Finished creating table.
Inserted a single book.
Inserted 3 rows of data.

Read data

Create a file named ReadData.java. This class fetches all rows from the books table and prints them.

package com.neon.quickstart;

import io.github.cdimascio.dotenv.Dotenv;
import java.sql.*;

public class ReadData {
    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();
        String connString = dotenv.get("DATABASE_URL");

        try (Connection conn = DriverManager.getConnection(connString);
             Statement stmt = conn.createStatement()) {
            System.out.println("Connection established");
            String sql = "SELECT * FROM books ORDER BY publication_year;";
            try (ResultSet rs = stmt.executeQuery(sql)) {
                System.out.println("\n--- Book Library ---");
                while (rs.next()) {
                    System.out.printf("ID: %d, Title: %s, Author: %s, Year: %d, In Stock: %b%n",
                            rs.getInt("id"), rs.getString("title"), rs.getString("author"),
                            rs.getInt("publication_year"), rs.getBoolean("in_stock"));
                }
                System.out.println("--------------------\n");
            }
        } catch (Exception e) {
            System.out.println("Connection failed.");
            e.printStackTrace();
        }
    }
}

The above code does the following:

  • Connects to the SerenDB database using the connection string from the .env file.

  • Executes a SQL query to select all rows from the books table, ordered by publication_year.

  • Iterates through the result set and prints each book's details.

Run the code to read the data using the following command:

mvn exec:java -Dexec.mainClass="com.neon.quickstart.ReadData"

When the read logic runs, it produces the following output:

Connection established

--- Book Library ---
ID: 2, Title: The Hobbit, Author: J.R.R. Tolkien, Year: 1937, In Stock: true
ID: 3, Title: 1984, Author: George Orwell, Year: 1949, In Stock: true
ID: 1, Title: The Catcher in the Rye, Author: J.D. Salinger, Year: 1951, In Stock: true
ID: 4, Title: Dune, Author: Frank Herbert, Year: 1965, In Stock: false
--------------------

Update data

Create a file named UpdateData.java to update the stock status of 'Dune' to True.

package com.neon.quickstart;

import io.github.cdimascio.dotenv.Dotenv;
import java.sql.*;

public class UpdateData {
    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();
        String connString = dotenv.get("DATABASE_URL");
        String sql = "UPDATE books SET in_stock = ? WHERE title = ?;";

        try (Connection conn = DriverManager.getConnection(connString);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            System.out.println("Connection established");
            pstmt.setBoolean(1, true);
            pstmt.setString(2, "Dune");
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("Updated stock status for 'Dune'.");
            }
        } catch (Exception e) {
            System.out.println("Connection failed.");
            e.printStackTrace();
        }
    }
}

The above code does the following:

  • Connects to the SerenDB database.

  • Prepares an SQL UPDATE statement to set the in_stock status of the book 'Dune' to true.

  • Executes the update and prints a confirmation message if successful.

Run the code to update the data using the following command:

mvn exec:java -Dexec.mainClass="com.neon.quickstart.UpdateData"

After running the update, verify the change by running the ReadData class again.

mvn exec:java -Dexec.mainClass="com.neon.quickstart.ReadData"

The updated output will be:

--- Book Library ---
ID: 2, Title: The Hobbit, Author: J.R.R. Tolkien, Year: 1937, In Stock: true
ID: 3, Title: 1984, Author: George Orwell, Year: 1949, In Stock: true
ID: 1, Title: The Catcher in the Rye, Author: J.D. Salinger, Year: 1951, In Stock: true
ID: 4, Title: Dune, Author: Frank Herbert, Year: 1965, In Stock: true
--------------------

You can see that the stock status for 'Dune' has been updated to true.

Delete data

Create a file named DeleteData.java to delete the book '1984' from the table.

package com.neon.quickstart;

import io.github.cdimascio.dotenv.Dotenv;
import java.sql.*;

public class DeleteData {
    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.load();
        String connString = dotenv.get("DATABASE_URL");
        String sql = "DELETE FROM books WHERE title = ?;";

        try (Connection conn = DriverManager.getConnection(connString);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            System.out.println("Connection established");
            pstmt.setString(1, "1984");
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("Deleted the book '1984' from the table.");
            }
        } catch (Exception e) {
            System.out.println("Connection failed.");
            e.printStackTrace();
        }
    }
}

The above code does the following:

  • Connects to the SerenDB database.

  • Prepares an SQL DELETE statement to remove the book '1984'.

  • Executes the delete and prints a confirmation message if successful.

Run the code to delete the data using the following command:

mvn exec:java -Dexec.mainClass="com.neon.quickstart.DeleteData"

After running the delete, verify the change by running the ReadData class again.

mvn exec:java -Dexec.mainClass="com.neon.quickstart.ReadData"

The final output will be:

--- Book Library ---
ID: 2, Title: The Hobbit, Author: J.R.R. Tolkien, Year: 1937, In Stock: true
ID: 1, Title: The Catcher in the Rye, Author: J.D. Salinger, Year: 1951, In Stock: true
ID: 4, Title: Dune, Author: Frank Herbert, Year: 1965, In Stock: true
--------------------

You can see that the book '1984' has been successfully deleted from the books table.

Next steps: Using an ORM or framework

While this guide demonstrates how to connect to SerenDB using raw SQL queries, for more advanced and maintainable data interactions in your Java applications, consider using an Object-Relational Mapping (ORM) framework. ORMs not only let you work with data as objects but also help manage schema changes through automated migrations keeping your database structure in sync with your application models.

Explore the following resources to learn how to integrate ORMs with SerenDB:

Source code

You can find the source code for the application described in this guide on GitHub.

Get started with Java and SerenDB using JDBC

Resources

Last updated