Programmatic Database Access

Learning Objectives

Pre-requisites

Lesson

In this lesson we will use SQLite, a lightweight SQL database commonly used in embedded devices such as phones and games consoles.

Adding a SQLite dependency

npm install sqlite3
In your pom.xml add:

        <!-- JDBI database connectivity -->
        <!-- JDBI is build on top of JDBC
        and provides a simpler interface -->
        <dependency>
            <groupId>org.jdbi</groupId>
            <artifactId>jdbi3-core</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- SQLite database -->
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.36.0.3</version>
        </dependency>

Checking database setup

Confirm you can connect to a in-memory SQLite database using the following code:

    const sqlite3 = require('sqlite3').verbose();

    // create an in-memory database
    const db = new sqlite3.Database(':memory:', (err) => {
        if (err) {
           return console.error(err.message);
        }
        console.log('Connected to the in-memory SQlite database.');
    });

    // close the database connection
    db.close((err) => {
        if (err) {
        return console.error(err.message);
        }
        console.log('Close the database connection.');
    });
Jdbi jdbi = Jdbi.create("jdbc:sqlite::memory:");
System.out.println('Connected to the in-memory SQlite database.');
// note that JDBI automatically takes care of releasing any connections after use

Inserting data

Now let's look at how we create a RESTAURANT table and insert rows into the table. Instead of storing the data in memory, we'll persist the database in a file named 'restaurants.sqlite'.

const sqlite3 = require('sqlite3').verbose();

function initialise() {
    // if the specified database exists, connect to it else create the database
    const db = new sqlite3.Database('./restaurants.sqlite');

    try {
        db.serialize(function () { 
            db.run("CREATE TABLE RESTAURANTS (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, imagelink TEXT)");

            let stmt;

            try {
                stmt = db.prepare(`INSERT INTO RESTAURANTS (name, imagelink) VALUES (?, ?)`);
                stmt.run('Bayroot', 'https://www.telegraph.co.uk/content/dam/Travel/Destinations/Europe/England/Brighton/brighton-restaurants-hotel-du-vin-bistro.jpg');
            } finally {
                // release resources 
                stmt.finalize();
            }
        
            // check the row was inserted ok
            db.each("SELECT * FROM Restaurants",
                function (err, rows) {  
                    console.log(rows);  
                }
            );
        });
    } finally { 
        // very important to always close database connections
        // else could lead to memory leaks
        db.close();
    }
}
        // if the specified database exists, connect to it else create the database
        Jdbi jdbi = Jdbi.create("jdbc:sqlite:restaurants.sqlite");

        // using withHandle will auto close the db connection
        List<Map<String, Object>> restaurants = jdbi.withHandle(handle -> {
            handle.execute("CREATE TABLE RESTAURANTS (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, imagelink TEXT)");
            handle.execute("INSERT INTO RESTAURANTS (name, imagelink) VALUES (?, ?)", "Bayroot", "https://www.telegraph.co.uk/content/dam/Travel/Destinations/Europe/England/Brighton/brighton-restaurants-hotel-du-vin-bistro.jpg");

            return handle.createQuery("SELECT * FROM RESTAURANTS")
                    .mapToMap()
                    .list();
        });

        System.out.println(restaurants);
    }

The code makes use of Prepared Statements/bind variables which are key for ensure your database applications are not vulnerable to SQL injection attacks. Watch this video to find out more about this kind of attack

Assignment

  1. Use the SQL you created in the SQL Joins lesson to create the Restaurant, Menu and MenuItems tables. Name the class/file InitialiseDB.

  2. Create a separate class/file called PopulateDB which contains code to insert a row into the Restaurant table and give the Restaurant two Menus. Insert two Menu Items per Menu.

  3. Write code to list all the Menu Items belonging to a specific Menu for a specific Restaurant.

  4. Commit your code into Github and share the link with your coach for review.

Assignment extension tasks

Additional resources