iBatis/Spring Beispielanwendung

In einem Kundenprojekt stand ich vor der Frage: Wieviel Hibernate muss es denn wirklich sein? Zwar bringt der Einsatz von Hibernate einige Vorteile mit sich, aber auf der anderen Seite bringt es auch ganz schön viel Overhead mit und ich bin mir nicht so ganz sicher, ob der Einsatz in vielen Fällen überhaupt sinnvoll ist.

Als "Alternative" habe ich mir Apache iBATIS mal etwas angeschaut und hab ein Beispiel zusammengestellt. Alles in allem ein interessanter Ansatz! Zwar muss man sich wieder mehr mit SQL herumärgern, aber vielleicht ist es auch das was man in manchen Fällen möchte ;-)

Das Beispiel gibts dann auch als Download. Es handelt sich um ein Eclipse basiertes Projekt, das über Maven 2 gebaut werden kann ('mvn package'). In der Spring Konfiguration muss noch die richtige Datenbankverbindung eingetragen werden. Bitte nicht zu viel erwarten, es ist absichtlich einfach gehalten. (download - 3,6 KB )

Das Beispiel

Es handelt sich um eine einfache Anwendung mit zwei Entitäten (Person und Organisation), die über eine Relation verbunden sind. Organisationen haben einen Chef.

Hier die zwei Entitäten:

package com.kkoehler.samples.ibatis.dom;

public class Person {

        private String name;    
        private Integer id;
        ...
}
package com.kkoehler.samples.ibatis.dom;

public class Organisation {

        private String id;
        private String name;
        private Person chef;
        ...
}

Also auch wieder POJOs. ;-)

Großer Unterschied zu Hibernate besteht darin, daß man kein Mapping für eine Entität angibt, sondern vielmehr sagt wie das Ergebnis eines bestimmten SQL Statements in Objekte gefüllt werden soll. Man könnte also ohne Probleme mehrere, unterschiedliche Personen- oder Organisationsobjekte füllen. Vielleicht hat der ein oder andere schon mal mehrere Value Objects (VOs) oder Data Transfer Objects (DTOs) aus einem Domain Objekt (DOM) befüllt, um eine Remote-Übertragung zu bewerkstelligen...

Hier ein Ausschnitt einer sqlMap-Datei, die das Mapping eines SELECT Statements auf ein Person Objekt bestimmt. Alle Felder werden in diesem Beispiel ausgelesen und gefüllt. Natürlich lassen sich hier auc einzelne Properties auswählen.

<sqlMap namespace="Person">

        <select id="getPerson" resultClass="com.kkoehler.samples.ibatis.dom.Person">
                select *
                from PERSON
                WHERE ID = #value#
        </select>
        ...
</sqlMap>

Dank der Spring Unterstützung sieht der aufrufende Code nicht sonderlich kompliziert aus. Wenn das eigene Data Access Objekt (DAO) von org.springframework.orm.ibatis.support.SqlMapClientDaoSupport erbt kann man ohne Probleme das SqlMapClientTemplate verwenden:

package com.kkoehler.samples.ibatis.dao.impl;

public class PersonDAOImpl extends SqlMapClientDaoSupport implements PersonDAO {

  public Person read(Integer id) {
    return (Person) getSqlMapClientTemplate().queryForObject("getPerson", id);
  }
  ...
}

Ähnlich funktioniert INSERT, UPDATE und DELETE der Objekte. Die Spring Konfiguration ist auch "straight forward" und nichts besonderes.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-2.5.xsd">

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                destroy-method="close">
                <property name="driverClassName" value="xxx" />
                <property name="url" value="jdbc:xxx" />
                <property name="username" value="xxx" />
                <property name="password" value="xxx" />
        </bean>

        <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
                <property name="configLocation" value="META-INF/ibatis/sqlmap-config.xml" />
                <property name="dataSource" ref="dataSource" />
        </bean>

        <bean id="personDAO" class="com.kkoehler.samples.ibatis.dao.impl.PersonDAOImpl">
                <property name="sqlMapClient" ref="sqlMapClient"/>
        </bean>

</beans>

Wie in der Spring Konfiguration zu sehen fehlt noch eine Konfigurationsdatei für iBATIS. Im Beispiel liegt sie unter META-INF/ibatis/sqlmap-config.xml und sieht wie folgt aus:

<?xml version="1.0"?>

<!DOCTYPE sqlMapConfig
  PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
  "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

        <sqlMap resource="META-INF/ibatis/Person.xml" />
        <sqlMap resource="META-INF/ibatis/Organisation.xml" />
        
</sqlMapConfig>

Und das war's im Großen und Ganzen auch schon. Mehr braucht man nicht ;-) Zugriff auf die DB geht wirklich flott von der Hand!

Noch ein paar Anmerkungen:

  • iBATIS bietet keine datenbankunabhängige Lösung
  • Ralations werden unterstützt
  • Caching und Lazy-Loading wird unterstützt
  • Man "darf" wieder SQL machen
  • Mehrere Objekte aus einer Tabelle sind kein Problem
  • Keine automatische Tabellengenerierung
  • Annotaions sollen kommen. Gibt es aber noch nicht