Today I've been playing with some of the new JDBC 4.0 features in the latest JDK6 beta. In particular, I've been scouting around for a lighter-weight alternative to Hibernate when working with small-sized projects, and one that uses annotations rather than XML.
A few weeks ago I tried out Ammentos, and although in the right direction it did not quite handle everything I threw at it. JDBC 4.0, however, seems just the thing with a little extra effort.
First some setup. After grabbing the latest JDK6 build I needed a database with a JDBC 4.0 driver. Some googling revealed that the also nifty Apache Derby database project is such a database, however only special daily builds have support turned on. Fair enough, it was only a download away and JDK6 is still in beta.
Finally, time for some code (ignoring imports, error handling and such):
public static void main(final String[] args) throws ClassNotFoundException, SQLException { Class.forName(EmbeddedDriver.class.getName()); final Connection connection = DriverManager.getConnection( "jdbc:derby:test-database;create=true"); final Statement statement = connection.createStatement(); statement.execute("CREATE TABLE BOB" + "(ID INT NOT NULL GENERATED ALWAYS AS IDENTITY," + " NAME VARCHAR(32))"); connection.setAutoCommit(false); connection.setTransactionIsolation(TRANSACTION_SERIALIZABLE); final BobQuery query = connection.createQueryObject(BobQuery.class); final String name = "the Builder"; final BobKeys key = query.addBob(name).get(0); final Bob bob = query.findBobByName(name).get(0); System.out.println("inserted = selected? " + key.id.equals(bob.id)); query.close(); statement.execute("DROP TABLE BOB"); connection.commit(); statement.close(); connection.close(); } public class Bob { public BigDecimal id; public String name; } @AutoGeneratedKeys public class BobKeys { public BigDecimal id; } public interface BobQuery extends BaseQuery { @Update(sql = "INSERT INTO BOB(name) VALUES(?1)", keys = RETURNED_KEYS_DRIVER_DEFINED) DataSetaddBob(final String name); @Select("SELECT * FROM BOB WHERE name = ?1") DataSet findBobByName(final String name); @Select("SELECT * FROM BOB") DataSet findAllBobs(); @Update("DELETE FROM BOB") int removeAllBobs(); }
Everything worked!
(And Derby helpfully creates a scratch database in-place given the proper JDBC URL.)
There were some gotchas:
- The Derby driver did not seem to use the new service feature at least for the embedded case shown here.
- The type for primary key identifiers is
BigDecimal
, notLong
as I guessed at. Improved javadocs would help here. - I had little luck with the
{fieldName}
syntax shown in the@Update
annotation javadocs for auto-generated keys. I am unsure if the driver, the JDK, the javadocs or the coder is at fault.
JDBC 4.0 is particularly well thought-out for custom persistence layers. I suspect much was borrowed conceptually from Hibernate's excellent work. To use the common DAO pattern as an example, just consider insertion:
public int addBob(final Bob bob) { final DataSetkeys = addBob(bob.getName()); if (keys.isEmpty()) return 0; bob.id = keys.get(0).id; return keys.size(); }
So much boilerplate code saved, a real boon to the coder in the trenches; the code is very readable; no SQLException
peppering the entire DAO layer. (Of course my curiosity rises: what does happen when the database cannot insert? — I need to read more on getSQLWarnings()
.)
JDBC 4.0 is nifty indeed.
UPDATE: As noted in one of the trackbacks, the Derby JDBC 4.0 driver now supports the service discovery mechanism. No more need to call Class.forName
. Excellent.
3 comments:
Hi
The new service feature is available in derby now got checked on 24th the day after you wrote the blog :).
You will need build 81 or latter of jdk1.6 (mustang) to use this feature.
The javadocs had a typo for the update annotation and {field} that functionality does not exist.
The EoD layer will throw a SQLRuntimeException which you can obtain the SQLException from if you desire
The new service feature worked fine -- thanks!
Post a Comment