The Unbearable Lightness of Java

DbSession

DbSession encapsulates database connection. It also plays nicely with DbQueryies and has some convenient features.

Connection providers

Connection provider is an object that provides connection from database when requested; and release one when not needed anymore. It encapsulates real mechanism how the database connection is actually retrieved and released.

Db offers several ConnectionProvider implementations: using DataSource, DriverManager, XADataSource or ConnectionPoolDataSource. More, Db has its own connection pool implementation, CoreConnectionPool, that works quite nicely.

Basic usage

DbSession uses ConnectionProvider for getting the actual database connections. Once created, DbSession are used for creating DbQuery-ies. DbSession takes care of created DbQuery instances during its session and closes all resources at the end: all queries and therefore all created result sets. At the end, DbSession returns connection back to ConnectionProvider. Here is an example of basic DbSession usage:

DbSession session = new DbSession(connectionProvider);   
... 
session.beginTransaction(); 
DbQuery query = new DbQuery(session, "insert into..."); 
query.executeUpdate(true);      // 'true' means that query will be closed after execution
session.commitTransaction();
....
query2 = new DbQuery(session, "select * from... "); 
ResultSet rs = query2.execute();
....
session.close();				// only session is explicitly closed :)

In above example only DbSession is explicitly closed. As said, DbSession keeps track of all created DbQueryies. On session closing, all open queries will be implicitly closed; therefore all created and still open ResultSet's will be closed. Even this is nice feature, some may like more to explicitly close each resource - with Db this is just matter of couple of lines anyway.

DbThreadSession

DbSession is open for extension for custom usage. One such extension already exists: DbThreadSession. Upon creation, it assigns created session to the current thread. From there, it is possible to retrieve the current session in any other part or layer of the application, without the need to carry it on through method arguments or any other way. This might be useful when one session (i.e. connection) is used per single thread, through application layers.

// create session and assign it to the thread
DbSession session = new DbThreadSession(connectionProvider);
...   
...// some layers in between
...
DbSession session = DbThreadSession.getCurrentSession(); 		// retrieve session from thread
DbQuery query = new DbQuery(session, "select...");
... 
...// going back
...
session.close();		// close session and remove it from thread storage

DbSessionProvider

Above code that works with DbQuery suffers from serious problem: it has strong dependency on concrete DbSession implementation! The goal would be to loose coupling between DbQuery and DbThreadSession on the place where DbQuery is used. Db has solution for this problem, too.

DbSessionProvider implementation is responsible for returning DbSession inside some context (thread, request...). This may be a new session or existing one. It is possible to register default DbSessionProvider implementation, so no DbSession has to be specified when creating new DbQuery. ThreadDbSessionProvider is default session provider and it manages sessions inside a thread. Above code may be re-written like this:

// create session and assign it to the thread
DbSession session = new DbThreadSession(connectionProvider);
...   
...// some layers in between
...
DbQuery query = new DbQuery("select...");	// no session refence is needed
... 
...// going back
...
session.close();		// close session and remove it from thread storage

When DbQuery is created without provided session or connection argument, it uses default session provider, which is, by default, ThreadDbSessionProvider. This provider returns assigned session from current thread. If no session is assigned, exception is thrown.

Alternatively, instead of throwin an exception, session can be created on demand and not every time, like in the above code. Some inner layer methods work with database and some don't, so sessions should be created only when really needed. ThreadDbSessionProvider offers variant for this case, too:

// in initialization, defined just once
DbSessionProvider sessionProvider = new ThreadDbSessionProvider(true);
DbDefault.sessionProvider = sessionProvider
...

// start, nothing is done here

...   
...// some layers in between
...
DbQuery query = new DbQuery("select...");	// no session refence is needed
... 
...// going back
...
sessionProvider.closeDbSession();		// or just: ThreadDbSessionProvider.closeThreadDbSession();

Now the database session is not explicitly created. It all happens in the background, first time when DbQuery is created. At the end, session has to be closed if it was open.

Transactions

DbSession works with transactions in expected way.

session.beginTransaction(new DbTransactionMode().isolationNone().setReadOnly(true)); 
try {
	DbQuery query = new DbQuery(session, "insert into..."); 
	query.executeUpdate(true);      // 'true' means that query will be closed after execution
	session.commitTransaction();
} catch(DbSqlException dbsex) {
	session.rollbackTransaction();
}
System.out.println(session.isTransactionActive());

Good idea is to create transaction mode objects once and use them through the application. The last row prints false, since transaction is not active anymore. When a session is not under transaction, it is in the auto-commit mode.

This is just basic transaction usage, Jodd offers more complex transaction management, using also propagations.