Jena2 Database Interface - How To Create Persistent Models

The Jena2  persistent storage subsystem implements an extension of the Model class that provides transparent persistence for models through the use of a database engine. Three database engines are currently supported, MySQL, Oracle, PostgreSQL and Microsoft SQL server, on both Linux and WindowsXP.

This document provides a brief overview of creating and accessing Jena2 persistent models. Users are now encouraged to use the factory mechanisms described in model-factory. Previous mechanisms based on directly calling ModelRDB methods are now deprecated.

The various options for configuring and accessing persistent models are described in Options.  For details on installing and configuring the various database engines for use with Jena2, see the database engine-specific "how to" documents (HSQLDB Howto, MySQL HowTo, Derby HowTo, PostgreSQL HowTo, Oracle HowTo, Microsoft SQL Server HowTo).

Creating and Accessing Persistent Models

In Jena2, all databases are multi-model and each model is, by default, stored in separate tables. Models may share database tables using the StoreWithModel option. Currently, model names may be any string however users are encouraged to use URIs as model names for compatibility with planned future Jena features. Note that the model name "DEFAULT" is reserved for use by Jena (as the name of the default model) and attempts to create such a named model will cause an exception.

As mentioned above, there are two mechanisms for creating persistent models, one using factory methods and another using constructors for the ModelRDB class. However, the factory methods do not return a ModelRDB instance. Consequently, certain methods defined on ModelRDB are not available for factory-created models, e.g., remove, setDoDuplicateCheck. If an application needs these methods, the ModelRDB constructors should be used. This is an interim measure until the factory-created models support all the ModelRDB capabilities. Below we review creating and opening models for each mechanism.

Factory Methods

Creating or opening a model is a three-step process. First, the driver class must be loaded and a connection established to the database (note that in Jena2, the database type is specified as part of the database connection). Second, a model maker class is constructed. The model maker creates persistent instances of the Model class. Third, the model maker class is invoked to create new models or to open existing models. The following examples show how this is done.

// database URL
String M_DB_URL         = "jdbc:mysql://localhost/test";
// User name
String M_DB_USER        = "test";
// Password
String M_DB_PASSWD      = "";
// Database engine name
String M_DB = "MySQL";
// JDBC driver
String M_DBDRIVER_CLASS = "com.mysql.jdbc.Driver";
// load the the driver class
Class.forName(M_DBDRIVER_CLASS);

// create a database connection
IDBConnection conn = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);

// create a model maker with the given connection parameters
ModelMaker maker = ModelFactory.createModelRDBMaker(conn);
// create a default model
Model defModel = maker.createDefaultModel();
...
// Open existing default model
Model defModel = maker.openModel();
 
// or create a named model
Model nmModel = maker.createModel("MyNamedModel");
...
// or open a previously created named model
Model prvModel = maker.openModel("AnExistingModel");

 

ModelRDB Methods

If using datbase-specific, low-level options (see "Options for Initialization and Access"), then the application may need to more directly use the ModelRDB interface.

Database-backed RDF models are instances of the class jena.db.ModelRDB which supports the full jena.model.Model interface and also provides static methods to create, extend and reopen database instances.

ModelRDB supports several options (see "Options for Initialization and Access"). Some options alter the underlying database table structure and must be specified before the database is formatted. These methods are invoked on the underlying database driver instance for the connection. Ideally, the driver class need not be exposed to Jena applications. Consequently, use of the driver class to set these options should be considered an interim measure until the option setting can be integrated into the factory methods. See Enabling URI Compression for an example of setting these options. Other options apply to models. See Disable Duplicate Checking for an example of setting these types of options.

Creating an instance of ModelRDB is a two-step process. As with the factory methods, the first step is to load the driver class and establish a database connection. Second, the static methods on ModelRDB are used to create new ModelRDB instances or to open existing ones. The following examples show how this is done.

// As before ...
String M_DB_URL          = "jdbc:mysql://localhost/test";
String M_DB_USER         = "test";
String M_DB_PASSWD       = "";
String M_DB              = "MySQL";
String M_DBDRIVER_CLASS  = "com.mysql.jdbc.Driver";
// load the the driver class
Class.forName(M_DBDRIVER_CLASS);

// create a database connection
IDBConnection conn = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);
 
// ---- Directly use ModelRDB
 
// create a default model
ModelRDB defModel = ModelRDB.createModel(conn);
...
// Open an existing model.
ModelRDB defModel2 = ModelRDB.openModel(conn);
...
// create a named model
ModelRDB nmModel = ModelRDB.createModel(conn,"MyModelName");
...
// open a named model
ModelRDB nmModel2 = ModelRDB.openModel(conn,"ExistingModelName");
...
 

Enable URI prefix compression

As an example of setting a database configuration option, the following shows how URI prefix compression is enabled. By default, URIs are stored fully expanded in the statement tables. Also shown is doubling the size of the prefix cache.

Class.forName(M_DBDRIVER_CLASS);
DBConnection dbcon = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);
dbcon.getDriver().setDoCompressURI(true);
ModelRDB model = ModelRDB.createModel(dbcon, "myModelName");
// double the size of the prefix cache
int cacheSize = dbcon.getDriver().getCompressCacheSize();
dbcon.getDriver().setCompressCacheSize(cacheSize*2);

Detect multiple models per database

In Jena2, all databases are multi-model and each model is, by default, stored in separate tables. Here is an example that checks to see if a specific named model exists and then creates or reopens it as necessary:

Class.forName(M_DBDRIVER_CLASS);
DBConnection dbcon = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);
ModelRDB model;
if( !dbcon.containsModel("myModelName")
	model = ModelRDB.createModel(dbcon, "myModelName");
else
	model = ModelRDB.open(dbcon, "myModelName");
Share tables among  models

In this example, a configuration option is used to specify that a new model should share the tables of an existing model. Unlike the previous option, this option can be set after the database is formatted. It affects only subsequently created models.

Class.forName(M_DBDRIVER_CLASS);
DBConnection dbcon = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);
ModelRDB model1, model2;
model1 = ModelRDB.createModel(dbcon, "myModel1");  // create a new model
dbcon.getDriver().setStoreWithModel("myModel1");
model2 = ModelRDB.createModel(dbcon, "myModel2"); // model2 is stored with model1

Disable duplicate checking

Some options apply to ModelRDB, e.g., query processing options. This example show how checking for duplicate statements can be disabled, as might be desirable when loading a large number of statements that the user is certain are duplicate-free.

Class.forName(M_DBDRIVER_CLASS);
DBConnection dbcon = new DBConnection(M_DB_URL, M_DB_USER, M_DB_PASSWD, M_DB);
ModelRDB model = ModelRDB.createModel(dbcon, "myModelName");
model.setDoDuplicateCheck(false);  // disable duplicate checking