1. Introduction
ActiveJDBC is a lightweight ORM following the core ideas of ActiveRecord, the primary ORM of Ruby on Rails.
It focuses on simplifying the interaction with databases by removing the extra layer of typical persistence managers and focuses on the usage of SQL rather than creating a new query language.
Additionally, it provides its own way of writing unit tests for the database interaction through the DBSpec class.
Let’s see how this library differs from other popular Java ORMs and how to use it.
2. ActiveJDBC vs Other ORMs
ActiveJDBC has stark differences compared to most other Java ORMs. It infers the DB schema parameters from a database, thus removing the need for mapping entities to underlying tables.
No sessions, no persistence managers, no need to learn a new query language, no getters/setters. The library itself is light in terms of size and number of dependencies.
This implementation encourages the usage of test databases which are cleaned up by the framework after executing the tests, thus reducing the cost of maintaining test databases.
However, a little extra step of instrumentation is needed whenever we create or update model. We’ll discuss this in coming sections.
3. Design Principles
- Infers metadata from DB
- Convention-based configuration
- No sessions, no “attaching, re-attaching”
- Lightweight Models, simple POJOs
- No proxying
- Avoidance of Anemic Domain Model
- No need of DAOs and DTOs
4. Setting Up the Library
A typical Maven setup for working with a MySQL database includes:
<dependency> <groupId>org.javalite</groupId> <artifactId>activejdbc</artifactId> <version>1.4.13</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency>
The latest version of activejdbc and mysql connector artifacts can be found on the Maven Central repository.
Instrumentation is the price of simplification and needed when working with ActiveJDBC projects.
There’s an instrumentation plugin which needs to be configured in the project:
<plugin> <groupId>org.javalite</groupId> <artifactId>activejdbc-instrumentation</artifactId> <version>1.4.13</version> <executions> <execution> <phase>process-classes</phase> <goals> <goal>instrument</goal> </goals> </execution> </executions> </plugin>
The latest activejdbc-instrumentation plugin can also be found in Maven Central.
And now, we can process instrumentation by doing one of these two commands:
mvn process-classes mvn activejdbc-instrumentation:instrument
5. Using ActiveJDBC
5.1. The Model
We can create a simple model with just one line of code – it involves extending the Model class.
The library uses inflections of the English language to achieve conversions of plural and singular forms of nouns. This can be overridden using the @Table annotation.
Let’s see how a simple model looks like:
import org.javalite.activejdbc.Model; public class Employee extends Model {}
5.2. Connecting to a Database
Two classes – Base and DB – are provided to connect to databases.
The simplest way to connect to a database is:
Base.open("com.mysql.jdbc.Driver", "jdbc:mysql://host/organization", "user", "xxxxx");
When models are in operation, they utilize a connection found in the current thread. This connection is put on the local thread by the Base or DB class before any DB operation.
The above approach allows for a more concise API, removing the need for DB Session or Persistence managers like in other Java ORMs.
Let’s see how to use the DB class to connect to a database:
new DB("default").open( "com.mysql.jdbc.Driver", "jdbc:mysql://localhost/dbname", "root", "XXXXXX");
If we look at how differently Base and DB are used to connect to databases, it helps us conclude that Base should be used if operating on a single database and DB should be used with multiple databases.
5.3. Inserting Record
Adding a record to the database is very simple. As mentioned before, there’s no need for setters and getters:
Employee e = new Employee(); e.set("first_name", "Hugo"); e.set("last_name", "Choi"); e.saveIt();
Alternatively, we can add the same record this way:
Employee employee = new Employee("Hugo","Choi"); employee.saveIt();
Or even, fluently:
new Employee() .set("first_name", "Hugo", "last_name", "Choi") .saveIt();
5.4. Updating Record
The snippet below shows how to update a record:
Employee employee = Employee.findFirst("first_name = ?", "Hugo"); employee .set("last_name","Choi") .saveIt();
5.5. Deleting Record
Employee e = Employee.findFirst("first_name = ?", "Hugo"); e.delete();
If there is a need to delete all records:
Employee.deleteAll();
If we want to delete a record from a master table which cascades to child tables, use deleteCascade:
Employee employee = Employee.findFirst("first_name = ?","Hugo"); employee.deleteCascade();
5.6. Fetching a Record
Let’s fetch a single record from the database:
Employee e = Employee.findFirst("first_name = ?", "Hugo");
If we want to fetch multiple records, we can use the where method:
List<Employee> employees = Employee.where("first_name = ?", "Hugo");
6. Transaction Support
In Java ORMs, there is an explicit connection or a manager object (EntityManager in JPA, SessionManager in Hibernate, etc.). There’s no such thing in ActiveJDBC.
The call Base.open() opens a connection, attaches it to the current thread and thus all subsequent methods of all models reuse this connection. The call Base.close() closes the connection and removes it from the current thread.
To manage transactions, there are are few convenience calls:
Starting a transaction:
Base.openTransaction();
Committing a transaction:
Base.commitTransaction();
Rolling back a transaction:
Base.rollbackTransaction();
7. Supported Databases
The latest version supports databases of likes SQLServer, MySQL, Oracle, PostgreSQL, H2, SQLite3, DB2.
8. Conclusion
In this quick tutorial, we focused on and explored the very basics of ActiveJDBC.
As always, the source code related to this article can be found over on Github.