miércoles, 24 de agosto de 2011

iBatis (MyBatis 3) - Configuración y ejemplos básicos

Este tutorial pretende explicar como configurar iBatis (ahora llamado MyBatis desde 2010) .

iBATIS es un framework (método de trabajo) de código abierto basado en capas desarrollado por Apache Software Foundation, que se ocupa de la capa de Persistencia (se sitúa entre la lógica de Negocio y la capa de la Base de Datos). Puede ser implementado en Javay .NET (también existe un port para Ruby on Rails llamado RBatis).
iBATIS asocia objetos de modelo (JavaBeans) con sentencias SQL o procedimientos almacenados mediante ficheros descriptores XML, simplificando la utilización de bases de datos.
Texto extraído de la wikipedia
A continuación explicaremos como se configura MyBatis (versión 3.0.5). Notamos que cambian algunas cosas con respecto a las versiones anteriores.

La tabla que utilizaremos en este tutorial es la siguiente

 CUSTOMER_ID     FIRST_NAME            GENDER     LAST_NAME     NAME1     NAME2     REFEREE_ID    
 --------------  --------------------  ---------  ------------  --------  --------  ------------- 
 1               cascadeMerge          FEMALE     Reclade       Damian    (null)    1             
 2               Damian Ciocca         (null)     (null)        (null)    (null)    (null)        
 3               First name 3          FEMALE     Last name 3   (null)    (null)    1             
 4               Miguel Angel Sanchez  MALE       Last name 4   (null)    (null)    (null)        
 100             Juan                  FEMALE     Lopez         (null)    (null)    10            
 300             pepe                  FEMALE     loria         (null)    (null)    10            
 200             pepe                  MALE       loria         name1     name2     10       


Archivo de configuracion de MyBatis (ConfigurationIbatis.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" />
<property name="username" value="hibernate_tutorial" />
<property name="password" value="hibernate_tutorial" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/ibatis/mappers/CustomerMapper.xml" />
</mappers>
</configuration>

En este archivo configuraremos ciertas propiedades, como por ejemploe, el DataSource JDBC y los mapeos SQL que utilizaremos en nuestra aplicación. Es decir, identificaremos todos los ficheros de mapeos XML usados en por MyBatis  para cargar los mapeos SQL (CustomerMapper.xml).


Archivo de mapeo SQL (CustomerMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="Customer">

<select id="getCustomerById" parameterType="int" 
    resultType="com.ibatis.domain.Customer">
SELECT CUSTOMER_ID as id, 
  FIRST_NAME as firstName, 
  LAST_NAME as lastName,
  GENDER as gender
FROM CUSTOMER C
WHERE C.CUSTOMER_ID = #{id}
</select>
<select id="getCustomerListByName" parameterType="string"
  resultType="com.ibatis.domain.Customer">
   SELECT CUSTOMER_ID as id, 
  FIRST_NAME as firstName, 
  LAST_NAME as lastName,
  GENDER as gender
FROM CUSTOMER C
WHERE C.FIRST_NAME like #{value}
    </select>
    
    <select id="getCustomerListByNameAndGender" parameterType="com.ibatis.domain.Customer" 
       resultType="com.ibatis.domain.Customer">
   SELECT CUSTOMER_ID as id, 
  FIRST_NAME as firstName, 
  LAST_NAME as lastName,
  GENDER as gender
FROM CUSTOMER C
WHERE C.FIRST_NAME like #{firstName} 
 AND C.GENDER = #{gender}
 
   </select>
   
   <insert id="insertCustomer" parameterType="com.ibatis.domain.Customer">
   
    INSERT INTO CUSTOMER(CUSTOMER_ID, FIRST_NAME, GENDER, LAST_NAME, NAME1, NAME2, REFEREE_ID) 
    values (#{id},#{firstName, jdbcType=VARCHAR},#{gender, jdbcType=VARCHAR},#{lastName, jdbcType=VARCHAR},
           #{name1, jdbcType=VARCHAR},#{name2, jdbcType=VARCHAR},#{refereeId, jdbcType=NUMERIC})
   
   </insert>
  
 
</mapper>


Interface java (CustomerMapper.java)

package com.ibatis.mappers;

import java.util.List;

import com.ibatis.domain.Customer;

public interface CustomerMapper {
Customer getCustomerById(int id);
List<Customer> getCustomerListByName(String firstName);
List<Customer> getCustomerListByNameAndGender(Customer customer);
void insertCustomer(Customer customer);

}


Clase que utilizaremos para mapear los resultados (Customer.java)

package com.ibatis.domain;

import java.io.Serializable;

public class Customer implements Serializable{
private int id;
private String firstName;
private String lastName;
private String gender;
private String name1;
private String name2;
private int refereeId;
public Customer() {
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getGender() {
return gender;
}

public void setGender(String gender) {
this.gender = gender;
}

public int getRefereeId() {
return refereeId;
}

public void setRefereeId(int refereeId) {
this.refereeId = refereeId;
}

public String getName1() {
return name1;
}

public void setName1(String name1) {
this.name1 = name1;
}

public String getName2() {
return name2;
}

public void setName2(String name2) {
this.name2 = name2;
}

@Override
public String toString() {
return "Customer [firstName=" + firstName + ", gender=" + gender
+ ", id=" + id + ", lastName=" + lastName + "]";
}

}


Clase de test para probar MyBatis (MyBatisTest.java)

package com.ibatis;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.ibatis.domain.Customer;

public class MyBatisTest {

public static void main(String[] args){

String resource = "com/ibatis/ConfigurationIbatis.xml";
try {
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sqlMapper.openSession();
try{
System.out.println("***********Customer.getCustomerById***************");
Customer customer = (Customer) session.selectOne("Customer.getCustomerById", new Integer(1));
System.out.println("Customer " + customer);
System.out.println("***********Customer.getCustomerListByName***************");
List<Customer> customers = session.selectList("Customer.getCustomerListByName", "%an%");
for (Customer customer2 : customers) {
System.out.println("Customer " + customer2);
}
System.out.println("*********Customer.getCustomerListByNameAndGender*****************");
Customer c = new Customer();
c.setFirstName("%an%");
c.setGender("FEMALE");
List<Customer> customers2 = session.selectList("Customer.getCustomerListByNameAndGender", c);
for (Customer customer3 : customers2) {
System.out.println("Customer " + customer3);
}
System.out.println("***********Customer.insertCustomer***************");
Customer c1 = new Customer();
c1.setId(300);
c1.setFirstName("pepe");
c1.setLastName("loria");
c1.setGender("FEMALE");
c1.setRefereeId(10);
session.insert("Customer.insertCustomer", c1);
session.commit();
} finally {
session.close();
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}


Resultado de la ejecución del test

***********Customer.getCustomerById***************
Customer Customer [firstName=cascadeMerge, gender=FEMALE, id=1, lastName=Reclade]
***********Customer.getCustomerListByName***************
Customer Customer [firstName=Damian Ciocca, gender=null, id=2, lastName=null]
Customer Customer [firstName=Miguel Angel Sanchez, gender=MALE, id=4, lastName=Last name 4]
Customer Customer [firstName=Juan, gender=FEMALE, id=100, lastName=Lopez]
*********Customer.getCustomerListByNameAndGender*****************
Customer Customer [firstName=Juan, gender=FEMALE, id=100, lastName=Lopez]
***********Customer.insertCustomer***************


Proyecto configurado en el eclipse


Anexo

Integración con Spring

MyBatis dispone de un módulo de integración con Spring Framework. El modulo permite que MyBatis participe en transacciones Spring. Permite también crear mappers y sesiones e inyectarlos en beans de servicio.

A continuación se muestra la definición del Mapper en Spring y su inyección en un bean de servicio denominado BlogService.

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>
<bean id="blogMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    <property name="mapperInterface" value="org.mybatis.example.BlogMapper" />
</bean>
<bean id="blogService" class="org.mybatis.example.BlogServiceImpl">
    <property name="blogMapper" ref="blogMapper" />
</bean>

Aquí vemos como al bean llamado blogService, Spring le inyecta el mapper de MyBatis (blogMapper) y de esta forma, para usar MyBatis simplemente hay que invocar al mapper inyectado.

public class BlogServiceImpl implements BlogService {

    private BlogMapper blogMapper;

    public void setBlogMapper(BlogMapper blogMapper) {
        this.blogMapper = blogMapper;
    }

    public void doSomethingWithABlog(int blogId) {
        Blog blog = mapper.selectBlog(blogId);
        ...
    }
}


5 comentarios: