IBATIS

Z Wikipedie, otevřené encyklopedie
Skočit na: Navigace, Hledání

iBATIS je aplikační framework, který usnadňuje mapování mezi SQL databázemi a objekty v Javě, .NET a Ruby on Rails. V Javě jsou těmito objekty jednoduché POJO. Mapování je odděleno od aplikační logiky tím, že se veškeré SQL dotazy ukládají do XML souborů. Výsledkem je minimalizace rutinní práce s JDBC.

Alternativní frameworky, jako například JPA, umožňují tvorbu objektového modelu vývojářem v Javě a pak vytvářejí a udržují databázi automaticky. iBATIS používá opačný přístup: vývojář nejdříve začne s SQL databází a iBATIS poté automatizuje tvorbu Java objektů. Oba přístupy mají své výhody, ale iBATIS je dobrá volba v případě, kdy vývojář nemá plnou kontrolu nad schématem SQL databáze. iBATIS v nejnovější verzi 3.0 nabízí velké množství vylepšení, i za cenu zpětné nekompatibility.

Použití v Javě[editovat | editovat zdroj]

Každá aplikace používající iBATIS se točí okolo instance třídy SqlSessionFactory. Tato instance může být získána pomocí třídy SqlSessionFactoryBuilder, která je schopná požadovanou třídu vytvořit na základě XML konfiguračního souboru nebo předpřipravené instance třídy Configuration.

Vytvoření SqlSessionFactory z XML souboru[editovat | editovat zdroj]

Vytvoření instance SqlSessionFactory z XML souboru je velmi jednoduché. iBATIS obsahuje pomocnou třídu Resource, která zjednodušuje načítání konfiguračních souborů z classpath a jiných míst.

String resource = "org/apache/ibatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);

Konfigurační XML soubor obsahuje nastavení pro iBATIS framework, včetně nastavení potřebného pro připojení k databázi a nastavení transakcí. Plný výčet možností je k naleznutí v uživatelské dokumentaci, jednoduchý příklad vypadá takto:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
  "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> 
<configuration>
  <environments default="production">
      <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
          <environment id="production">  
         <transactionManager type="MANAGED">  
             <property name="" value=""/>  
         </transactionManager>  
         <dataSource type="POOLED">  
             <property name="driver" value="${driver}"/>  
             <property name="url" value="${url}"/>  
             <property name="username" value="${username}"/>  
             <property name="password" value="${password}"/>  
             <property name="poolMaximumActiveConnections" value="25"/>  
             <property name="poolMaximumIdleConnections" value="5"/>  
         </dataSource>  
     </environment>
  </environments>
  <mappers>
    <mapper resource="org/apache/ibatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

Za zmínku zde určitě stojí podpora rozlišení různých běhových prostředí, což je novinka od verze 3.0. Pomocí tagu <environment> máme možnost definovat různé nastavení pro připojení k databázi a poté je měnit pomocí jednoduché konfigurace.

Vytvoření SqlSessionFactory bez použití XML[editovat | editovat zdroj]

iBATIS nabízí třídu Configuration, která poskytuje stejné konfigurační možnosti, jako XML soubor.

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = 
	new Environment("development ", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = 
	new SqlSessionFactoryBuilder().build(configuration);

V tomto případě potřebujeme navíc ještě takzvanou mapper třídu, která obsahuje SQL mapovací anotace, abychom se vyhnuli potřebě XML. Z důvodu omezení Java anotací a komplexnosti některých mapování jsou XML stále potřeba pro nejsložitější mapování (např. Nested Join Mapping).

Získávání SqlSession z SqlSessionFactory[editovat | editovat zdroj]

Nyní, když už máme SqlSessionFactory, můžeme získat instanci třídy SqlSession. Tato třída obsahuje všechny metody potřebné pro vykonávání SQL dotazů do databáze. Mapované SQL příkazy je možné provádět přímo proti tomuto objektu. Například:

SqlSession session = sqlMapper.openSession();
try {
  Blog blog = (Blog) session.select(
    "org.apache.ibatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}

I když tento přístup funguje, je zde daleko přehlednější přístup. Použitím rozhraní, které přesně popíše parametry a návratové hodnoty pro daný příkaz, je možné docílit daleko čistějšího a typově bezpečného kódu. Například:

SqlSession session = sqlSessionFactory.openSession();
try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
} finally {
  session.close();
}

Mapované SQL příkazy[editovat | editovat zdroj]

Příkazy mohou být definované buď pomocí XML, nebo anotací. Pojďme se nejdříve podívat na XML. Úplnou sadu funkcí poskytovaných iBATISem lze realizovat pomocí mapovacího jazyku založeného na XML, který učinil iBATIS tak populární v průběhu posledních let. Zde je příklad s mapováním pomocí XML, které by umožnilo úspěšné volání výše uvedené SqlSession.

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper 
    PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" 
    "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> 
<mapper namespace="org.apache.ibatis.example.BlogMapper"> 
  <select id="selectBlog" parameterType="int" resultType="Blog"> 
    select * 
from Blog 
where id = #{id} 
  </select> 
</mapper>

Tato ukázka definuje mapovaný příkaz“selectBlog”, ve jmenném prostoru “org.apache.ibatis.example.BlogMapper”. Následující ukázka demonstruje použití anotací pro stejný účel:

package org.apache.ibatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

Anotace mají své omezení a nehodí se na složitější konstrukce. Update, delete Update ani Delete se od Selectu moc neliší.

<select id="selectBlog" parameterType="int" resultType="Blog"> 
  select * 
          from Blog 
          where id = #{id} 
</select> 
 
<update id="updateBlog" parameterType="Blog">
  update Blog set 
title = #{title}
  where id = #{id}
</update>
 
<delete id="deleteBlog” parameterType="int">
    delete from Blog where id = #{id}
</delete>

Dynamické SQL[editovat | editovat zdroj]

Velmi zajímavá je také podpora dynamických SQL dotazů pomocí OGNL. Používají se čtyři základní podmínkové elementy: • if • choose (when, otherwise) • trim (where, set) • foreach

<select id="findActiveBlogLike"
        parameterType="Blog" resultType="Blog">
    SELECT * FROM BLOG WHERE state = ‘ACTIVE’
    <if test="title != null">
        AND title like ${title}
    </if>
    <if test="author != null && author.name != null">
        AND title like ${author.name}
    </if>
</select>
 
<select id="findActiveBlogLike"
        parameterType="Blog" resultType="Blog">
    SELECT * FROM BLOG WHERE state = ‘ACTIVE’
    <choose>
        <when test="title != null">
            AND title like ${title}
        </when>
        <when test="author != null && author.name != null">
            AND title like ${author.name}
        </when>
        <otherwise>
            AND featured = 1
        </otherwise>
    </choose>
</select>
 
<select id="selectPostIn" resultType="domain.blog.Post">
    SELECT *
    FROM POST P
    WHERE ID in
    <foreach item="item" index="index" collection="list"
             open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

Element trim (popřípadě where a set) řeší situace, kde by podmínka v určité části dotazu mohla působit vytvoření nevalidního SQL dotazu. Například, pokud bychom v prvním případě odstranili podmínku „state = ‘ACTIVE’”, mohli bychom dojít k dotazu SELECT * FROM BLOG WHERE Pokud by se obě podmínky vyhodnotili jako nepravda. iBATIS má ovšem pro tyto situace velmi jednoduché řešení v podobě elementu where:

<select id=”findActiveBlogLike” 
parameterType=”Blog” resultType=”Blog”>
  SELECT * FROM BLOG 
  <where> 
  	<if test=”state != null”>
     		state = #{state}
  	</if> 
  	<if test=”title != null”>
    		AND title like #{title}
  	</if>
  	<if test=”author != null and author.name != null”>
    		AND title like #{author.name}
  	</if>
	  </where>
</select>

Pokud bychom s chováním where elementu nebyli spokojeni, můžeme si nadefinovat vlastní chování pomocí elementu trim. Takto by vypadal ekvivalent k elementu where:

<trim prefix="WHERE" prefixOverrides="AND |OR "></trim>

Nástroje[editovat | editovat zdroj]

Ibator je generátor kódu pro iBATIS. Z existující relační struktury je schopen vygenerovat kód POJO class, SqlMap.xml obsahující CRUD dotazy a DAO interface a implementaci. Může být použit na začátku projektu nebo opakovaně i v rámci build cyklu (pomocí Antu).