What's iBATIS, or iBATIS vs. Hibernate
As of December 2006, iBATIS has been simplified to perform one function, and only one function: data mapping. While iBATIS used to support a DAO layer, this has been deprecated in favour of using Spring and IoC. This article will stick to discussing the data mapper; for more information on the DAO implementation, please refer to the Spring framework documentation (specifically here). The key documentation for iBATIS is the Developer Guide, with the very latest here in the SVN repository.
OK, on to Hibernate vs. iBATIS...
- While they've both involved with having your application persist & retrieve data, comparing them is an "apples vs. oranges" comparison, in that while they both do the job, they're significantly different in certain ways.
Fundamentally, iBATIS maps Java Objects to the results of SQL Queries, whereas Hibernate maps Java Objects directly to database tables, traditional Object-Relational Mapping. The benefits of Hibernate are that it automatically generates all the SQL for your and the cache invalidation can be more fine grained. iBATIS is more flexible especially if you are a strong SQL query writer. You have control over exactly how the SQL queries are written.
Another way of looking at it to say that Hibernate works well if you have mostly standard queries(CRUD, Find by Criteria, etc.) and if you are designing your object model first. If you are working with a legacy system or a schema designed by a DBA, iBATIS often makes a better choice. Of course, we're not discussing absolutes here, they're both much better than raw SQL!
The thing with iBATIS is that there isn't a whole lot of magic, and you get full control over the SQL, so you can see what's going on and how to change it. Compared to other frameworks, it has a shorter learning curve, but can take more time to develop and maintain, since you have to write all your queries (using Abator can short-circuit this step) and if your object model changes you have to go through all your queries and make sure to make all the necessary changes to reflect the changes in your object model.
While there's nothing particularly special about the use of iBATIS within a Wicket application, the normal Wicket requirement of ensuring that things that you store in your pages are Serializable mean that you may need to be careful how you store references to DAO-type objects.
The following is intended to suggest one way in which this might be done.
Note: While this example uses Spring and the SpringBean annotation, neither are strictly required, but they do simplify things enough that I felt it was worth using them, even without any previous knowledge of them.
- EntryDao : An interface describing the DAO operations we want, e.g. count, find, load, save, delete
- EntryDaoImpl : An implementation of the DAO. For Spring/IBATIS, this will extend
SqlMapClientDaoSupportand make the DB call using a definition in an SqlMap relating to the Item.
- Entry.map.xml : IBATIS SqlMap definitions, one per operation.
Another take on the above may be obtained by using the Abator code generator tool - See below.
An interface describing the DAO operations we want, e.g. load, save, delete, etc.
An implementation of the DAO.
the particular schema this is accessing is a simple Name/Value/LastChanged one, i.e. No distinct id
IBATIS SqlMap definitions, one per operation.
A couple of notes:
- I'm using the Oracle SYSDATE keyword, but I could have made if DB-neutral if needed. However, as the app this example is derived from will only be deployed on Oracle, I didn't!
deleteblock is just a placemarker. The actual name, i.e. "value", isn't significant there, unlike the names used in the
insertsections where they're used to determine the JavaBean accessors to use.
Typical Wicket Spring Initialisation
Typical Wicket Spring Application
Just for completeness...
This contains the 'global' settings for iBATIS and the collection of SQL maps in use. When using together with Spring, it can be very concise...
Note that the Spring TransactionProxyFactoryBean is serializable, so we can do the following in the Wicket component as long as our application extends AnnotSpringWebApplication.
Note: If we don't want to/can't use
@SpringBean then there are other options available, e.g. [ storing the DAO in the Application|Spring#Application_Object_Approach ], etc.
iBATIS SqlMapClientTemplate does have a
queryForList(String statementName, Object parameterObject, int skipResults, int maxResults) method, but note that it works by obtaining all the elements(keys) from the DB then just returning the selected part of the list. If wanting to handle this more efficiently, it's down to the (DB-specific) SQL.
Oracle's paging is rather involved due to it's particular implementation of ROWNUM. However, this example shows how it can work. (It also shows a bit more too, e.g. dynamic & sortable SQL, but that's not the main point here!)
In the DaoImpl, set up a 'map' data structure to pass various things in.
In the Entry.sql.map, the variables are taken from the Map passed in.
dynamicsection is more complex than needed for the example, as it caters for multiple sub-elements. The idea is that you have multiple blocks and the first time one triggers, the
prependfrom the outer
dynamicblock overrides the
prependfrom the inner block.
- If using XML 'reserved' chars, e.g. < or >, you'll need to escape them with CDATA sections.
- The variables are used in 3 different ways in this example
- The 'normal' #name# method
- As a test, e.g.
<isNotNull property="name" ...
- To create dynamic SQL, e.g. ORDER BY $sort$
Abator - Code Generator for iBATIS (Recommended!)
See http://ibatis.apache.org/docs/tools/abator/ for documentation.
Abator is a code generator for iBATIS that will examine a database table/tables and generate iBATIS artefacts that can be used to access the table(s).
Abator seeks to make a major impact on the large percentage of database operations that are simple CRUD (Create, Retrieve, Update, Delete). You will still need to hand code SQL and objects for custom queries, or stored procedures, but it generates code that should cover much of the required usage (See Using the Abator Generated Objects) and provide a good basis for creating the rest.
Abator will generate:
- SqlMap XML Files
- Java Classes to match the primary key and fields of the table(s)
- Abator Generated Java Model Classes
- Java 'Example' classes to help with selecting subsets of the tables(s)
- DAO Interfaces & DAOImpl Classes that use the above objects. Various formats (e.g. IBATIS, SPRING, etc)
Abator can run as a standalone JAR file, or as an Ant task, or as an Eclipse plugin.
I'd really recommend starting with this, as it proves a good jump-start!