一個iBatis的demo

相對Hibernate和Apache OJB 等“一站式”ORM解決方案而言,ibatis 是一種“半
自動化”的ORM實現。
所謂“半自動”,可能理解上有點生澀。縱觀目前主流的ORM,無論Hibernate 還是
Apache OJB,都對數據庫結構提供了較爲完整的封裝,提供了從POJO 到數據庫表的全
套映射機制。程序員往往只需定義好了POJO 到數據庫表的映射關係,即可通過Hibernate
或者OJB 提供的方法完成持久層操作。程序員甚至不需要對SQL 的熟練掌握,
Hibernate/OJB 會根據制定的存儲邏輯,自動生成對應的SQL 並調用JDBC 接口加以執
行。 ----摘自官方資料的一段話

iBatis是一種很好的解決方案,使用起來很靈活,參考一些網絡中的資料我也想把自己的使用過程寫下來,如有錯誤希望指正。

環境:JDK1.5+Eclipse3.2 使用時僅需要在Eclipse中導入項目。

首先是表結構, 提供了兩種數據庫的支持分別爲MySQL與hsqldb,可以根據實際情況選擇使用。以MySQL爲例:
[code]create database if not exists `ibatis_schema`;

USE `ibatis_schema`;

drop table if exists `t_user`;

CREATE TABLE `t_user` (
`id` int(12) NOT NULL auto_increment,
`name` varchar(50) default NULL,
`date` date default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=GBK;

Insertinto `t_user`(name,date) values('liulu','2007-03-15'),('liulu2','2007-03-15'),('liulu3','2007-03-15');
[/code]
然後是iBatis的配置文件 SqlMapConfig.xml
這裏進行數據源的配置以及一些參數的設置和優化
[code]<?xml version="1.0" encoding="UTF-8" ?>

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

<sqlMapConfig>

<settings cacheModelsEnabled="true" useStatementNamespaces="true" />
<transactionManager type="JDBC">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
<property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost/ibatis_schema" />
<property name="JDBC.Username" value="root" />
<property name="JDBC.Password" value="1234" />
</dataSource>
</transactionManager>

<sqlMap resource="com/javaeye/liulu/maps/User.xml" />
</sqlMapConfig>
[/code]
User.java就是domain了,是映射的對象。
[code]package com.javaeye.liulu.domain;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable{
private int id;
private String name;
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[/code]
下面是比較重要的SQL Map XML映射文件,所有方法都在這裏。
User.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="User">
<typeAlias alias="UserObject" type="com.javaeye.liulu.domain.User" />
<resultMap id="userResult" class="UserObject">
<result property="id" column="id" jdbcType="NUMBER" />
<result property="name" column="name" jdbcType="VARCHAR2" />
<result property="date" column="date" jdbcType="DATE" />
</resultMap>

<select id="getByPK" resultMap="userResult" parameterClass="UserObject">
<![CDATA[
select
id,
name,
date
from t_user
where id = #id#
]]>
</select>

<select id="getById" resultMap="userResult" parameterClass="java.lang.String">
<![CDATA[
select
id,
name,
date
from t_user
where id = $String$
]]>
</select>

<sql id="Dy_SC">
<dynamic prepend="WHERE">
<isNotNull prepend="AND" property="id">id like #id#</isNotNull>
<isNotNull prepend="AND" property="name">name like #name#</isNotNull>
</dynamic>
</sql>

<select id="getUser" resultMap="userResult">
<![CDATA[
select
id,
name,
date
from t_user
]]>
<include refid="Dy_SC" />
</select>

<insert id="insertUser" parameterClass="UserObject">
INSERT INTO t_user (name,date) VALUES (#name#,#date#)
</insert>

<insert id="insertUserTest" parameterClass="UserObject">
INSERT INTO t_user (id,name,date) VALUES (#id#,#name#,#date#)
</insert>

<update id="updateUser" parameterClass="UserObject">
<![CDATA[
UPDATE t_user
SET
name=#name#,
date=#date#
WHERE id = #id#
]]>
</update>

<delete id="deleteUser" parameterClass="java.lang.String">
delete from t_user where id=#value#
</delete>

<statement id="getMaxId" resultClass="java.lang.Integer">
select Max(id) from t_user
</statement>

<statement id="getMax" resultClass="java.util.HashMap">
select Max(id) as id,Max(name) as name,Max(date) as date from t_user
</statement>

</sqlMap>
[/code]
這樣就可以來測試了,測試也使用了兩種方法,先使用一個普通應用程序來測試一下程序的運行好了。
[code]package com.javaeye.liulu;

import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.ibatis.common.jdbc.ScriptRunner;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.javaeye.liulu.domain.User;

public class Main {

//hsql初始化,對MySQL沒有影響
static {
try {
Properties props = Resources.getResourceAsProperties("properties/database.properties");
String url = props.getProperty("url");
String driver = props.getProperty("driver");
String username = props.getProperty("username");
String password = props.getProperty("password");
if (url.equals("jdbc:hsqldb:mem:ibatisDemo")) {
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url, username, password);
try {
ScriptRunner runner = new ScriptRunner(conn, false, false);
runner.setErrorLogWriter(null);
runner.setLogWriter(null);
runner.runScript(Resources.getResourceAsReader("ddl/hsql/ibatisdemo-hsqldb-schema.sql"));
runner.runScript(Resources.getResourceAsReader("ddl/hsql/ibatisdemo-hsqldb-dataload.sql"));
} finally {
conn.close();
}
}
} catch (Exception e) {
throw new RuntimeException("Description. Cause: " + e, e);
}
}

/**
* 初始化iBatis獲得一個SqlMapClient對象
*
* @param
* @return SqlMapClient
*/
public static SqlMapClient getSqlMapClient() {
String resource = "com/javaeye/liulu/maps/SqlMapConfig.xml";
SqlMapClient sqlMap = null;
try {
Reader reader = Resources.getResourceAsReader(resource);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
} catch (Exception e) {
e.printStackTrace();
}
return sqlMap;
}

/**
* 插入一條記錄
*
* @param
* @return
*/
public static void insert() {
SqlMapClient sqlMap = getSqlMapClient();
try {
sqlMap.startTransaction();
User user = new User();
user.setName("insert1");
user.setDate(new Date());
sqlMap.insert("User.insertUser", user);
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* 將第一條記錄的信息更新
*
* @param
* @return
*/
public static void update() {
SqlMapClient sqlMap = getSqlMapClient();
try {
sqlMap.startTransaction();
User user = (User)sqlMap.queryForObject("User.getById", "1");
user.setName("update1");
sqlMap.update("User.updateUser", user);
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
sqlMap.endTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

/**
* 刪除id最大的記錄
*
* @param
* @return
*/
public static void delete() {
SqlMapClient sqlMap = getSqlMapClient();
try {
sqlMap.startTransaction();
String maxId = sqlMap.queryForObject("User.getMaxId", null).toString();
sqlMap.delete("User.deleteUser", maxId);
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* 根據name查詢User爲Map的List
*
* @param
* @return List
*/
public static List getUser() {
SqlMapClient sqlMap = getSqlMapClient();
List<User> user = null;
try {
sqlMap.startTransaction();
HashMap params = new HashMap();
params.put("name", "%liulu%");
user = sqlMap.queryForList("User.getUser", params);
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
sqlMap.endTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}
return user;
}

/**
* 查詢各個字段的最大值(一般用於統計,此處演示使用方法)
*
* @param
* @return
*/
public static void getMax() {
SqlMapClient sqlMap = getSqlMapClient();
try {
sqlMap.startTransaction();
Map search = (HashMap) sqlMap.queryForObject("User.getMax", null);
System.out.println(search.get("id").toString() + "\n"
+ search.get("name").toString() + "\n"
+ search.get("date").toString());
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* 通過主鍵查找,返回user
*
* @param
* @return
*/
public static void getByPK() {
SqlMapClient sqlMap = getSqlMapClient();
User user = new User();
try {
sqlMap.startTransaction();
user.setId(1);
user = (User) sqlMap.queryForObject("User.getByPK", user);
System.out.println(user.getId() + "\n" + user.getName() + "\n"
+ user.getDate());
sqlMap.commitTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
//insert();
//update();
//delete();

List<User> user = getUser();
for (User o : user) {
System.out.println("id:" + o.getId() + "\nname:" + o.getName()
+ "\nDate:" + o.getDate() + "\n------------");
}
//getMax();
//getByPK();
}
}
[/code]
所有的方法都是靜態的,可以分別對映射方法進行測試。

下面使用的是單元測試對iBatis來測試,使用了dbunit這個開源項目。
首先,要爲單元測試準備數據。使用DbUnit,我們可以用XML文件來準備測試數據集。
t_user對應表名
id,name,date分別對應列名

user_seed.xml
[code]<?xml version="1.0" encoding="GBK"?>
<dataset>
<t_user id="1"
name="liulu"
date="2007-01-01"/>

<t_user id="2"
name="liulu2"
date="2007-03-15"/>

<t_user id="3"
name="liulu3"
date="2007-03-18"/>
</dataset>
[/code]
方便測試,首先爲SqlMap的單元測試編寫一個抽象的測試基類
[code]package com.javaeye.liulu.test;

import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

import javax.sql.DataSource;

import org.dbunit.DatabaseTestCase;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;

import com.ibatis.common.resources.Resources;
import com.ibatis.db.util.ScriptRunner;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public abstract class BaseSqlMapTest extends DatabaseTestCase {
protected static SqlMapClient sqlMap;

protected IDatabaseConnection getConnection() throws Exception {
return new DatabaseConnection(getJdbcConnection());
}
protected void setUp() throws Exception {
super.setUp();
init();
}
protected void tearDown() throws Exception {
super.tearDown();
getConnection().close();
if (sqlMap != null) {
DataSource ds = sqlMap.getDataSource();
Connection conn = ds.getConnection();
conn.close();
}
}
protected void init() throws Exception {
initSqlMap("com/javaeye/liulu/maps/SqlMapConfig.xml", null);
}
protected SqlMapClient getSqlMapClient() {
return sqlMap;
}
protected void initSqlMap(String configFile, Properties props)
throws Exception {
Reader reader = Resources.getResourceAsReader(configFile);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader, props);
reader.close();
}
protected void initScript(String script) throws Exception {
DataSource ds = sqlMap.getDataSource();
Connection conn = ds.getConnection();

Reader reader = Resources.getResourceAsReader(script);
ScriptRunner runner = new ScriptRunner();
runner.setStopOnError(false);
runner.setLogWriter(null);
runner.setErrorLogWriter(null);

runner.runScript(conn, reader);
conn.commit();
conn.close();
reader.close();
}
private Connection getJdbcConnection() throws Exception {
/*
Properties props = new Properties();
props.load(Resources.getResourceAsStream("properties/database.properties"));
Class driver = Class.forName(props.getProperty("driver"));
Connection conn = DriverManager.getConnection(props.getProperty("url"),
props.getProperty("username"), props.getProperty("password"));
*/
Class driver = Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/ibatis_schema","root","1234");
return conn;
}
}
[/code]
然後爲每個SqlMap映射文件編寫一個測試用例,extends上面的抽象類
[code]package com.javaeye.liulu.test;

import java.io.Reader;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;

import com.ibatis.common.resources.Resources;
import com.javaeye.liulu.domain.User;

public class UserTest extends BaseSqlMapTest {

protected IDataSet getDataSet() throws Exception {
Reader reader = Resources.getResourceAsReader("com/javaeye/liulu/test/user_seed.xml");
return new FlatXmlDataSet(reader);
}

public void testGetByPK() throws Exception {
User user = new User();
user.setId(1);
user = (User) sqlMap.queryForObject("User.getByPK", user);
assertNotNull(user);
assertEquals(user.getId(), 1);
assertEquals(user.getName(), "liulu");
assertEquals(user.getDate().getDay(), 1);
}

public void testGetUser() throws Exception {
List users = null;
HashMap params = new HashMap();
params.put("name", "%liulu%");
users = (List) sqlMap.queryForList("User.getUser", params);
assertEquals(users.size(),3);
}

public void testInsertUser() throws Exception {
User user = new User();
user.setId(4);
user.setName("insert1");
user.setDate(new Date());
sqlMap.insert("User.insertUserTest", user);

User user2 = new User();
user2.setId(4);
user2 = (User) sqlMap.queryForObject("User.getById", "4");
assertEquals(user.getId(),user2.getId());
assertEquals(user.getName(),user2.getName());

}

public void testUpdateUser() throws Exception {
User user = (User)sqlMap.queryForObject("User.getById", "1");
user.setName("liulu7");
sqlMap.update("User.updateUser", user);
User user2 = (User)sqlMap.queryForObject("User.getById", "1");
assertEquals(user2.getName(),"liulu7");
}

public void testDeleteUser() throws Exception {
int num = sqlMap.delete("User.deleteUser", "1");
assertEquals(num,1);
}

public void testGetMaxId() throws Exception {
int i = (Integer)sqlMap.queryForObject("User.getMaxId", null);
assertEquals(3,i);
}

}
[/code]
注意,其中測試insert時由於id爲auto_increment,可能需要對測試數據中<dataset/>進行設置,網絡中並未查詢到相關的方法,所以在映射文件中加入了一個
[code]<insert id="insertUserTest" parameterClass="UserObject">
INSERT INTO t_user (id,name,date) VALUES (#id#,#name#,#date#)
</insert>
[/code]
用例測試中測試的是insertUserTest,並非insertUser,請注意。

到這裏就結束了,demo比較簡單,希望能給大家帶來幫助。

參考:
http://ibatis.apache.org/
http://hsqldb.org/
http://www.dbunit.org/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章