Skip to content

Database in the Cloud

Heroku does not play well with SQLite

SQLite runs in memory, and backs up its data store in small files on disk that are easily created and moved around. While easy to use, SQLite is not intended as a production grade database. In particular, SQLite will not play well with Heroku because Heroku uses an ephemeral filesystem; you can write to it, and you can read from it, but the contents will be cleared periodically. If you were to use SQLite on Heroku, you would lose your entire database at least once every 24 hours!

PostgreSQL database

Heroku provides production grade PostgreSQL databases as a service. PostgreSQL database can be used by any language and framework, and it is very easy to connect your Java App to it; you'll need to change your JDBC driver but probably not much else.

First, add the JDBC driver for PostgreSQL to your project dependencies:

1
compile 'org.postgresql:postgresql:42.2.10'

Let's write a sample code to demonstrate the process of connecting to Heroku Postgres. Here is the main method from last reading; I added a call to workWithDatabase() at the end:

1
2
3
4
5
6
public static void main(String[] args) {
  final int PORT = getHerokuAssignedPort();
  Javalin app = Javalin.create().start(PORT);
  app.get("/", ctx -> ctx.result("Hello Heroku!"));
  workWithDatabase();
}

Here is the implementation of workWithDatabase():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private static void workWithDatabase(){
  try (Connection conn = getConnection()) {

    String sql = "CREATE TABLE IF NOT EXISTS Courses(" +
                    "name VARCHAR(30) NOT NULL," +
                    "url VARCHAR(100)" +
                 ");";
    Statement st = conn.createStatement();
    st.execute(sql);

    sql = "INSERT INTO Courses(name, url) VALUES ('oose', 'jhu-oose.com');";
    st.execute(sql);

  } catch (URISyntaxException | SQLException e) {
    e.printStackTrace();
  }
}

The workWithDatabase is a very simple example of using JDBC to (1) establish a Connection to a SQL database and (2) execute two SQL statements to create a table and insert a record into it. Note the use of getConnection() method; here is the implementation for it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
private static Connection getConnection() throws URISyntaxException, SQLException {
  String databaseUrl = System.getenv("DATABASE_URL");
  if (databaseUrl == null) {
    // Not on Heroku, so use SQLite
    return DriverManager.getConnection("jdbc:sqlite:./Store.db");
  }

  URI dbUri = new URI(databaseUrl);

  String username = dbUri.getUserInfo().split(":")[0];
  String password = dbUri.getUserInfo().split(":")[1];
  String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':' 
        + dbUri.getPort() + dbUri.getPath() + "?sslmode=require";

  return DriverManager.getConnection(dbUrl, username, password);
}

When we were working with SQLite, we used a URI like jdbc:sqlite:./Store.db to instantiate a JDBC connection in your code. Heroku puts the URI of the PostgreSQL database in a environment variable DATABASE_URL. We can directly get the DATABASE_URL in code. The DATABASE_URL for the Heroku Postgres follows the below convention

1
postgres://<username>:<password>@<host>:<port>/<dbname>

However, the Postgres JDBC driver uses the following convention:

1
jdbc:postgresql://<host>:<port>/<dbname>?user=<username>&password=<password>

The code in getConnection() converts the Heroku DATABASE_URL into a JDBC URI.

Warning

The example above uses SQLite when you are not on Heroku and PostgreSQL database when you are on Heroku. This is only for demonstration purposes. It is important that you use the same database in production as in development. So, if you are going to deploy your app on Heroku, you will need to install the PostgreSQL database locally.

PostgreSQL Add-on

Before you deploy your app to Heroku, you need to create the Heroku Postgres add-on for your app using the Heroku CLI; open the terminal at the root directory of your Java project and type the following command:

1
$ heroku addons:create heroku-postgresql

Deploy

Finally, run the following command to deploy your app:

1
$ ./gradlew build deployHeroku

To checkout the Postgres database provisioned for your app (and its content) you can use third-party tools like https://heroku-data-explorer.herokuapp.com/ or https://www.adminer.org/. Alternatively, install PostgreSQL locally and connect it to Heroku Postgres following the instructions here.

Here is the repository of a the sample code above, for your reference.