Question

I'm writing a Java application that uses SQLite via JDBC for persistence.

What I need to do when the application starts is:

  1. If the DB doesn't exists, create it with the right schema
  2. If the DB exists, check if the DB has the right schema

In order to create the DB I thought of externalizing the SQL commands needed to create the structure (e.g. CREATE TABLE ...) in an external file, load it at runtime and execute it. I thought of using BufferedReader with .readLine() and then feed each SQL command to a Statement.executeUpdate(). Is there some smarter way to do this?

Concerning the startup check of the database schema, while I think that this should be considered "good design", I don't know if in practice it could be overkill or useless. One solution I came up with but has the disadvantage of being "vendor dependent" is this:

  1. Create the DB by using a known prefix for all the structures' names (e.g. nwe_)
  2. Query the sqlite_master table with WHERE name LIKE 'nwe_%'
  3. Compare the content of the SQL column with the SQL command file I used for creating the DB

Again, is there some smarter way to do this? (maybe not "vendor dependent", but this at the time is not much of an issue for me)

Thanks.

Was it helpful?

Solution

You can write up your own verification of the database by looking in the metdata tables. This is not impossible, but it is a lot of code to maintain. You can also write up a lot of DDL statements to construct the database structures, again not impossible, but a lot of code to maintain.

If you follow such a path, I recommend a higher-level logic of

if (!checkDatabase()) {
  try {
    if (wantsToInstall()) {
      installDatabase();
    }
  } catch (Exception e) {
    exit();
  }
}

or a specific installer (to reduce the chance of installing over existing items). Extensions that provide deleting data items can be done, but there are differing opinions as to what to do if encountering an unexpected pre-existing object during install / upgrade.

Now there are a few libraries that will do this for you; but by the time they add this feature, such a library probably takes care of much more than simple database structure maintenance. Look to JDO and a few others, I know that DataNucleus's environment will gladly create database structures tweaked to work well in just over 20 different databases (remember they all have subtle differences in how they do things).

OTHER TIPS

I'm not a professional programmer and this is my first java application, but I decided to do database verification too. Fortunately, sqlite databases has a system table with sql statements for each table in database. So there is a fast and dirty way to check database structure:

public class Model {
    private Map<String, String> tableSql;

    Model(){
        // declare right database's tables syntax 
        tableSql = new HashMap<String, String>();
        tableSql.put("settings",    "CREATE TABLE [settings] ( [id]     INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [item] ... )");
        tableSql.put("scheta",      "CREATE TABLE [scheta] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [sname] ...)");
        tableSql.put("nomera",      "CREATE TABLE [nomera] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [nvalue] ...)");
        tableSql.put("corr",        "CREATE TABLE [corr] (  [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cname] ...)");
        tableSql.put("category",    "CREATE TABLE [category] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cname] ...)");
        tableSql.put("price",       "CREATE TABLE [price] ( [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [cdate] ...)");
    }

    public void Connect( String path){
        File DBfile = new File (path);
        boolean DBexists = DBfile.exists();
        Statement stmt = null;
        ResultSet rs;

        try {
            Class.forName("org.sqlite.JDBC");
            c = DriverManager.getConnection("jdbc:sqlite:" + path);
            c.setAutoCommit(true);

            stmt = c.createStatement();
            if( DBexists ){
                // check database structure
                for (String tableName : tableSql.keySet()) {
                    rs = stmt.executeQuery( "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = '" + tableName + "'");
                    if(rs.isBeforeFirst()){
                        rs.next();
                        // table and field names may be inside square brackets or inside quotes...
                        String table_schema_there = rs.getString(1).replaceAll("\\s+"," ").replaceAll("[\\[\\]'`]", "\"");
                        String table_schema_here = tableSql.get(tableName).replaceAll("\\s+"," ").replaceAll("[\\[\\]'`]", "\"");;
                        if( ! table_schema_there.equals(table_schema_here) ){
                            notifyListeners( new ModelResponse( false, "Structure error. Wrong structure of table "  + tableName));
                            System.exit(0);
                        }
                    }
                    else{
                        notifyListeners( new ModelResponse( false, "Structure error. The table is missing: "  + tableName ));
                        System.exit(0);
                    }
                }
            }
            else{
                // empty DB file created during connection so we need to create schema
                for (String tableName : tableSql.keySet()) {
                    stmt.executeUpdate(tableSql.get(tableName));
                }
            }
        } 
        catch ( Exception e ) {
            notifyListeners( new ModelResponse( false, e.getMessage()));
            System.exit(0);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top