6

I want to create a program which users run just by running a .jar file. I want this program to have access to a database, which is pre-filled with some data when the program is first downloaded, and as the user uses it, more data is added to the db.

The db should be locally stored on the user's computer.

What is my best option for this? Which database engine should I go with, and what do I have to do to make it so the user won't have to setup the db when he installs the app, it will come pre-filled with the .jar file?

Ali
  • 261,656
  • 265
  • 575
  • 769

2 Answers2

7

A simple solution would be to use an embedded database stored locally on the disk (for example near the jar file). You can use h2, or even sqlite for this.

When loaded the program will check for the existence of the database, if it's not here, just play a setup SQL script that will create the database structure and initial data, otherwise you're good to go, just do the stuff that your application was created to do.

Here is a really simple example with h2 database:

Say you are packaging a SQL file named init.sql in the /resources/ folder of your JAR, that will create a table, something like:

create table foobar(bazz VARCHAR);
insert into foobar values('foo');
insert into foobar values('bar');
// and so on

Then somewhere in your code, where you need to access the data you will try to load the DB or create it if it does not exists yet.

Connection loadDatabase() throws Exception {
    Class.forName("org.h2.Driver");
    Connection con = null;
    try {
        // throws an exception if the database does not exists
        con = DriverManager.getConnection("jdbc:h2:./foo.db;ifexists=true");
    } catch (SQLException e) {
        // if the database does not exists it will be created
        conn = DriverManager.getConnection("jdbc:h2:./foo.db");
        // init the db
        initDatabase(con);
    }

    return con;
}

void initDatabase(Connection con) throws Exception {
    // load the init.sql script from JAR
    InputStreamReader isr = new InputStreamReader(
        getClass().getResourceAsStream("/resources/init.sql"));
    // run it on the database to create the whole structure, tables and so on
    RunScript.execute(con, isr);
    isr.close();
}

void doSomeStuffWithDb() throws Exception {
    Connection con = loadDatabase();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select * from foobar");
    // will print foo, then bar
    while (rs.next()) {
        System.out.println(rs.getString(1));
    }
    rs.close();
    stmt.close();
    conn.close();
}

After execution, you should have a file named foo.db next to your application where lies the created tables etc.

This is a really simple example, of course you can use any wrapper around JDBC to avoid use of ResultSet etc, like spring jdbcTemplate, even to load the connection instance etc.

Alex
  • 25,147
  • 6
  • 59
  • 55
  • SQLite will be a bit more tricky because it's native code. Or is there some sort of pre-packaged cross-platform deployment wizardry for it? – Tom Anderson Oct 18 '12 at 19:01
  • Yes you're right about SQLite, I did not really realized it as it's being already installed on my dev machine, but yes, he should prefer h2 for this if he does not want to involve the user in installing something else – Alex Oct 18 '12 at 19:06
  • Heh. I also sometimes have this problem of software being installed on my machine by helpful sysadmins that i then don't realise is not available everywhere! – Tom Anderson Oct 18 '12 at 19:07
1

I would look into h2. It's a great database with many persisting options. Also since you're using Java, I would consider looking into hibernate.

Kurtymckurt
  • 337
  • 2
  • 6