to robbin
ibatis的網站
www.ibatis.com上面可以找到很好的文檔,再加上有非常不錯的例子,所以使用是相當的簡單。
sourceforge上面的討論
http://swik.net/DAO
http://www.learntechnology.net/struts-ibatis.do
http://www.nabble.com/iBATIS-f360.html
http://www.cjsdn.net/post/page?bid=20&sty=3&tpg=2&s=73&age=0
https://sourceforge.net/forum/forum.php?forum_id=206693
http://www.cjsdn.net/post/view?bid=11&id=172565&sty=1&tpg=1&age=0Windows
環境下的tomcat + apache配置(絕對實踐操作版)
ibatis大體上可以分為兩個部分:SQL Maps + Data Access Objects
我現在的項目中都用到了,它提供的jpetstore就使用了db layer,可以參考它的實現方式。
不過我覺得jpetstore的db layer實現方式還不是太好,至少它的業務邏輯層和dao層沒有明顯區分,在實現比較
大的項目的時候造成了程序的混亂,如果沒有一個良好的模式來實現db layer 的時候,確實會造成效率的低下,
有了良好的架構,速度確實很快(特別是SQL Maps + Data Access Objects 都使用的情況)
BO層的設計已經不是什么新鮮的了,但我覺得它確實可以很好的和DaoManager結合起來,通過DaoManager->SQL
map->jdbc
它的兩個核心的配置文件:dao.xml+SqlMapConfig.xml
通過靈活的配置文件的組合可以實現數據庫不同的訪問組合
比如:一個dao.xml可以對應多個SqlMapConfig.xml
一個dao.xml可對應一個數據庫,多個dao.xml就可以訪問多個數據庫了(它的petstore就提供了演示distributed
功能的樣例是oracle+ms sql)
它的SqlMapConfig.xml中可配置sql-map resource,就是配置你具體的sql語句的xml文件。
它的sqlMap提供很多方法來訪問數據庫,直接返回你想要的結果
***************************
DAO中的一個供分頁查詢的方法
***************************
......
SqlMap sqlMap = getSqlMapFromLocalTransaction();//取到當前sqlmap對象
List list=sqlMap.executeQueryForList("你的MappedStatement文件中sql語句的名稱", object("你可以通過這
個object傳一些查詢條件"),skipResults,maxResults);
...
有了良好的設計模式,它可以和struts完美結合在一起,無論是效率還是清晰型上,都非常令人滿意的
public void saveUser(User user)
??? {
??????? if (user.getId() == null)
??????? {
??????????????? Long id = (Long) getSqlMapClientTemplate().insert("addUser", user);
??????????? logger.info("new User id set to: " + id);
??????? } else {
??????????? getSqlMapClientTemplate().update("updateUser", user);
??????? }
???????
??? }???
domain is the central business tier. service package is more like a web package, just a way to
expose these services remotely, so that users could use the web interfaces, or the webservice
interfaces(like amazon's webservices).
//TestA.javapublic class TestA{public static void main(String[] args){TestA a=new TestA
();System.out.println(a.getClass().getClassLoader());TestB b=new TestB();b.print
();}}//TestB.javapublic class TestB{public void print(){System.out.println(this.getClass
().getClassLoader());}}
DAO(data access objects)允許你去創建簡單的組件,為你訪問你的數據,而不用去實現具體的實現細節。使用
DAOS你能動態配置不同的持久層機制。
注意:DAO框架與sqlmaps框架是完全的分離開和互不依賴性,所以你可以單獨使用,或一起來用都沒有關系.
下面是一些重要的daos api
DaoManager(Facade模式):負責配置DAO框架實例(經過dao.xml),在其它api當中充當facade.
DaoTransaction(Marker Interface):通用的接口,為了去使用事物(連接),通用的實現將包裝jdbc的連接對象
.
DaoException(RuntimeException運行期異常):所有的方法和類全部拋出dao api專有的異常。
Dao(Marker Interface):一個標記接口供所有的dao去實現,這個接口必須為所有的dao類去實現。這個接口沒有
聲名任何方法被實現,只是充當一個標記(例如:一些DaoFactory去辯別不同的類);
-----------------------------------
jdbc事務控制實現
sqlmap:通過sqlmaps框架和它的事物管理服務去實現,包括不同的DataSource和事物管理配置
hibernate:提供簡單容易的和hibernate,它的事物工具(SessionFactory,Session,Transaction)整合
jdbc:通過jdbc api,使用它的基本的dataSource和Connction接口去管理事物
jta:管理分部式事物,需要被管理的datasource,這樣子可以通過jndi訪問.
external:允許事物被外部控制
dao.xml為配置文件(http://www.ibatis.com/dtd/dao-2.dtd)
DaoManager負責配置dao框架。DaoManager類可以為框架解析特定的xml文件,而提供出有用的信息供框架使用。
那么配置文件(xml文件)需要指定下面的內容:
1)dao的上下文
2)事物為每一個上下文件的實現
3)TransactionManager配置屬性
4)Dao為每一個實現的dao接口
一個Dao上下文是一組相關的配置信息和Dao實現。通常一個上下文關聯到一個數據源(datasource)或一個文件。
dao配置文件(通常被叫做dao.xml,但不是必須的),為下面的結構
<!DOCTYPE daoConfig
PUBLIC "-//iBATIS.com//DTD DAO Configuration 2.0//EN"
"<
daoConfig>
<properties resource="com/domain/properties/MyProperties.properties"/>
<!-- Example JDBC DAO Configuration -->
<context>
<transactionManager type="JDBC">
<property name="DataSource" value="SIMPLE"/>
<property name="JDBC.Driver" value="${driver}"/>
<property name="JDBC.ConnectionURL" value="${url}"/>
<property name="JDBC.Username" value="${username}"/>
<property name="JDBC.Password" value="${password}"/>
<property name="JDBC.DefaultAutoCommit" value="true" />
<property name="Pool.MaximumActiveConnections" value="10"/>
<property name="Pool.MaximumIdleConnections" value="5"/>
<property name="Pool.MaximumCheckoutTime" value="120000"/>
</transactionManager>
<dao interface="com.domain.dao.OrderDao"
implementation="com.domain.dao.jdbc.JdbcOrderDao"/>
<dao interface="com.domain.dao.LineItemDao"
implementation="com.domain.dao.jdbc.JdbcLineItemDao"/>
<dao interface="com.domain.dao.CustomerDao"
implementation="com.domain.dao.jdbc.JdbcCustomerDao"/>
</context>
<!-- Example SQL Maps DAO Configuration -->
<context>
<transactionManager type="SQLMAP">
<property name="SqlMapConfigResource" value="com/domain/dao/sqlmap/SqlMapConfig.xml"/>
</transactionManager>
<dao interface="com.domain.dao.PersonDao"
implementation="com.domain.dao.sqlmap.SqlMapPersonDao"/>
<dao interface="com.domain.dao.BusinessDao"
implementation="com.domain.dao.sqlmap.SqlMapBusinessDao"/>
<dao interface="com.domain.dao.AccountDao"
implementation="com.domain.dao.sqlmap.SqlMapAccountDao"/>
</context>
</daoConfig>
一個dao.xml里可以有多個context,通常一個上下文指定一個特定的dataSource
為了去管理多樣的配置(因為有不同的環境),你可以使用可選的元素<properties).
這個允許使用占用符,例如:
driver=org.postgresql.Driver
url=jdbc:postgresql://localhost:5432/test
這時你可以在dao.xml里用占用符取代具體的值,例如上面的可以改寫成下面的
<property name="JDBC.Driver" value="${driver}"/>
<property name="JDBC.ConnectionURL" value="${url}"/>
在上下文當中,第一個context里同使用的是jdbc事物控制,所以在指定的property元素也要使用jdbc,不同的事
物管理實現會需要不同的properties,
事物管理實現(Transaction Manager Implementation and Configuration)是一個組件會管理pool(事物對象)
,一事物管理通常只是包裝特定的DataSource,簡單的事物通常包裝一特定的實現類如jdbc連接實現
jdbc Transaction Manager:利用提供的datasource api提供連接池服務
有三種datasource是支持的(simple,dbcp,jndi),simple是實現了ibatis的SimpleDataSource。dbcp使用了
jakarta dbcp datasource,最后,jndi是實現了查找datasource是從jndi上去查
下面是不同的配置方法
<!-- Example iBATIS SimpleDataSource JDBC Transaction Manager -->
<transactionManager type="JDBC">
<property name="DataSource" value="SIMPLE"/>
<property name="JDBC.Driver" value="${driver}"/>
<property name="JDBC.ConnectionURL" value="${url}"/>
<property name="JDBC.Username" value="${username}"/>
<property name="JDBC.Password" value="${password}"/>
<property name="JDBC.DefaultAutoCommit" value="true" />
<!-- The following are optional -->
<property name="Pool.MaximumActiveConnections" value="10"/>
<property name="Pool.MaximumIdleConnections" value="5"/>
<property name="Pool.MaximumCheckoutTime" value="120000"/>
<property name="Pool.TimeToWait" value="10000"/>
<property name="Pool.PingQuery" value="select * from dual"/>
<property name="Pool.PingEnabled" value="false"/>
<property name="Pool.PingConnectionsOlderThan" value="0"/>
<property name="Pool.PingConnectionsNotUsedFor" value="0"/>
</transactionManager>
<!-- Example Jakarta DBCP JDBC Transaction Manager -->
<transactionManager type="JDBC">
<property name="DataSource" value="DBCP"/>
<property name="JDBC.Driver" value="${driver}"/>
<property name="JDBC.ConnectionURL" value="${url}"/>
<property name="JDBC.Username" value="${username}"/>
<property name="JDBC.Password" value="${password}"/>
<property name="JDBC.DefaultAutoCommit" value="true" />
<!-- The following are optional -->
<property name="Pool.MaximumActiveConnections" value="10"/>
<property name="Pool.MaximumIdleConnections" value="5"/>
<property name="Pool.MaximumWait" value="60000"/>
<!-- Use of the validation query can be problematic. If you have difficulty, try without it. -->
<property name="Pool.ValidationQuery" value="select 1 from ACCOUNT"/>
<property name="Pool.LogAbandoned" value="false"/>
<property name="Pool.RemoveAbandoned" value="false"/>
<property name="Pool.RemoveAbandonedTimeout" value="50000"/>
</transactionManager>
<!-- Example JNDI DataSource JDBC Transaction Manager -->
<transactionManager type="JDBC">
<property name="DataSource" value="JNDI"/>
<property name="DBJndiContext" value="java:comp/env/jdbc/MyDataSource"/>
</transactionManager>
jta管理事物:它使用的是jta api.實種實現總是需要通過jndi去獲得datasource和一個UserTransaction實例也
是通過jndi訪問的,因些需要在服務器配置一下,不過這使得配置dao框架十分簡單了。下面是一個簡單的配置
<transactionManager type="JTA">
<property name="DBJndiContext" value="java:comp/env/jdbc/MyDataSource"/>
<property name="UserTransaction" value="java:comp/env/UserTransaction"/>
</transactionManager>
sqlmap管理事物:通過dao框架包裝sql maps事物服務,所有的你都要指定一個sql maps配置文件。下面是一個簡
單的配置
<transactionManager type="SQLMAP">
<property name="SqlMapConfigResource" value="com/domain/dao/sqlmap/SqlMapConfig.xml"/>
</transactionManager>
hibernate管理事物:同樣的,通過dao框架包裝hibernate事物服務,基本上properties在配置文件當中和
hibernate.properties文件是一樣的,另外,持久化類(你可能通過添加到hibernate配置文件當中去的)要
以"class."開頭,下面是一個例子:
<transactionManager type="HIBERNATE">
<property name="hibernate.dialect" value="net.sf.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.connection.driver_class" value="${driver}"/>
<property name="hibernate.connection.url" value="${url}"/>
<property name="hibernate.connection.username" value="${username}"/>
<property name="hibernate.connection.password" value="${password}"/>
<property name="class.1" value="com.domain.Person"/>
<property name="class.2" value="com.domain.Business"/>
<property name="class.3" value="com.domain.Account"/>
</transactionManager>
external 管理事物:允許使用dao框架控制。這個執行基本是沒有行為,因些不需要properties,如果你使用一個
flat file,你可以使用external事物管理,
<transactionManager type="EXTERNAL"/>
dao實現模板:你可能要問我怎么使用上面的事物,好了每一種事物類型都要相應的dao模板與之對應。例如:
jta,jdbc模板提供簡單的訪問jdbc連接對象。相似的sqlmap模板提供訪問簡單的SqlMapExecutor實例,而
hibernate template提供訪問Session object.
使用dao template完全是可選的,但99%的時間里,是不可不選擇的/
更多的模板請看下面的.
DaoManager編程:iBATIS dao框架有許多的目的.第一個,它試圖持久層的細節.這包括所有的接口,實現和異
常細節(在你的持久層解決方案當中).
例如:如果你使用jdbc,dao框架將為你隱藏類如DataSource,Connection和SQLException.類似的,如果你使用
Hibernate orm,dao框架會為你隱藏類如Configuration,SessionFactory,Session和HibernateException.所有的
這些細節都會隱藏到了dao接口層.甚至在顯示層的許多的datasource也會被隱藏.
第二個目的是:簡化持久層編程模型,使在同一時間保持一致.不同的持久層解決方案有不同的編程語義和行為.
dao框架試圖隱藏更多,允許在你的應用service和domain層,寫出一致的風格.
DaoManager類負責dao框架的配置文件(通過dao.xml),另外,DaoManage扮演著中心門面的角色,它特殊之處是,還提
供方法允許你訪問事物和dao實例.
讀取配置文件:
使用DaoManagerBuilder類的靜態方法buildDaoManager()方法讀取dao.xml文件,buildDaoManager()方法需要一個
Reader實例作為參數.
例如:
Reader reader = new FileReader(C:/myapp/dao.xml);
DaoManager daoManager = DaoManagerBuilder.buildDaoManager(reader);
如在web應用環境當中(或其它),一般配置文件都會從classpath當中去加載的.我們可以使用
com.ibatis.common.resources.Resources類
Reader reader = Resources.getResourceAsReader(“com/domain/config/dao.xml”);
DaoManager daoManager = DaoManagerBuilder.buildDaoManager(reader);
Context和DaoManager
DaoManager實例是從dao.xml文件建立的.當你需要一個dao實例時,你可以通過DaoManager,和事物控制也會從它此
處提供的.因些不需直接訪問context和事物管理..
你的dao知道它怎么去做.類似的,需要看你的daos怎么工作的,事物會恰當的開始和提交的.而且,事物僅在你的dao
被調用時才啟動.
獲取dao實例
一旦你得到了DaoManager實例,你就可以根據dao名字,利用DaoManager的getDao方法獲取該dao實例了,如:
ProductDao productDao = (ProductDao) daoManager.getDao (ProductDao.class);
DaoManager提供了處理事務的方法.這些方法允許你劃分事務,和避免傳遞事務對象(eg:jdbc Connction)到你的所
有的daos當中去.例如:
ProductDao productDao = (ProductDao) daoManager.getDao (ProductDao.class);
try {
daoManager.startTransaction();
Product product = productDao.getProduct (5);
product.setDescription (“New description.”);
productDao.updateProduct(product);
daoManager.commitTransaction();
} finally {
daoManager.endTransaction();
}
調用startTransaction()只是讓DaoManager知道,你將要啟動編程控制事務.
dao實例化時才啟動事務的,甚至事務僅僅是contexts需要的時候.
commitTransaction()提交事務,endTransaction()需要在try{}catch(){}里面的,,
如果發現了異常,那么就會回滾.
自動提交事務
像jdbc的setAutoCommit(true)一樣,不過也有不同之處,你可以使用多個update作為一個事務,你不需要指定提交
的行為方式,只要你不調用startTransaction()就行了
Product product = productDao.getProduct (5); // Transaction 1
product.setDescription (“New description.”);
productDao.updateProduct(product); // Transaction 2
product = productDao.getProduct (5); // Transaction 3
注意了,這里沒有異常的事件發生的,如發生異常,就會回滾,和釋放連接資源的.
實現自己的dao接口:
dao接口非常的簡單,因為它沒有聲名任何的方法,只是一個marker interface,所以實現的只是你自己的接口罷了,
在你的接口當中沒有限制你要定的任何方法,拋出的異常是運行期的DaoException類型的異常.
An example of a good Dao interface is:
public interface ProductDao extends Dao {
// Updates
public int updateProduct (Product product); // DAO Framework code may throw DaoException
public int insertProduct (Product product);
public int deleteProduct (int productId);
/
/ Queries
public Product getProduct (int productId);
public List getProductListByProductDescription (String description);
}
Templates和Implementations
在上面也提到了,每一種模板都對應一種特殊的Transaction Manager.
每一種模板提供了一種便利的方法去交互.
template Class?????? Transaction Manager??????? Convenience Method
JdbcDaoTemplate????? JDBC?????????????????????? Connection getConnection()
JtaDaoTemplate?????? JTA??????????????????????? Connection getConnection();
SqlMapDaoTemplate??? SQLMAP???????????????????? SqlMapExecutor getSqlMapExecutor()
HibernateDaoTemplate? HIBERNATE??????????? ?Session getSession()
The following is an example implementation using the SqlMapDaoTemplate:
public class SqlMapProductDao implements ProductDao extends SqlMapDaoTemplate {
public SqlMapProductDao (DaoManager daoManager) {
super (daoManager);
}
/
* Insert method */
public int updateProduct (Product product) {
try {
getSqlMapExecutor().insert (“insertProduct”, product);
} catch (SQLException e) {
throw new DaoException (“Error inserting product. Cause: “ + e, e);
}
}
/
/ … assume remaining methods to save space
}
注意:在上面的例子里只有一些個構造器,參數為DaoManager,它是在初始化實例時通過DaoManagerBuilder自動注
入參數進去..第一個需要DaoManager作為構造器的參數,也就迫使它的子類都要一個帶參(DaoManager)的構造器,
當你使用模板時,構造器是必須的,你不需要提供其它的構造器了..你的daos僅僅需要DaoManagerBuilder去實例化
它.
考慮dao的設計方式:
推薦使用一個繼承dao接口的接口,另一個為一個繼承dao接口的抽象類(封閉一些異常,事務等等)..
實際上你只需要一個就行了,另外你也可以選擇下面這種方式..
你可以使用BaseJdbcDao(abstract)繼承dao接口,需讓ProductDao不要去斷承dao接口,讓ProductJdbcDao去實現
ProductDao和繼承BaseJdbcDao就可以了,讓Product接口仍然與dao分離開來....
在上面的例子當中可以將BaseJdbcDao繼承JdbcDaoTemplate(它已經實現了dao接口)
現在做一個例子:
create table test
(
id int auto_increment;
name varchar(20)
);
建一個對應的vo
package zhai;
public class test {
?int id;
?String name;
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;
}
}
建一個配置數據庫的配置文件
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
??? PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
??? "<sqlMapConfig>
? <transactionManager type="JDBC">
??? <dataSource type="SIMPLE">
????? <property value="com.mysql.jdbc.Driver" name="JDBC.Driver"/>
????? <property value="jdbc:mysql://localhost:3306/test" name="JDBC.ConnectionURL"/>
????? <property value="root" name="JDBC.Username"/>
????? <property value="root" name="JDBC.Password"/>
??? </dataSource>
? </transactionManager>
? <sqlMap url="file:C:\Test\sql.xml"/>
</sqlMapConfig>
--
sql.xml
--------
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
??? "
<sqlMap namespace="test">
? <typeAlias alias="test" type="test.test"/>
? <select id="getByName" resultClass="test" parameterClass="string">
??? SELECT
???? ID,
???? NAME
??? FROM TEST
??? WHERE NAME = #name#
? </select>
</sqlMap>
----------------
------------------
package zhai;
public interface MyDao {
? public void MyInsert(test t);
}
==================
package zhai;
import java.sql.SQLException;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.template.SqlMapDaoTemplate;
public class TestDao extends SqlMapDaoTemplate implements MyDao{
?public TestDao(DaoManager arg0) {
??super(arg0);
??// TODO Auto-generated constructor stub
?}
?public void MyInsert(test t) {
??try {
???getSqlMapExecutor().insert ("insertTest",t);
??} catch (SQLException e) {
???System.out.println("插入時出異常");
???e.printStackTrace();
??}
?}
}
============
package zhai;
import java.io.*;
import com.ibatis.sqlmap.client.*;
public class TestDemo {
?public static void main(String[] args) throws Exception {
??Reader reader=new FileReader("C:\\Test\\config.xml");
???? SqlMapClient sqlmap=SqlMapClientBuilder.buildSqlMapClient(reader);
???? test emp = (test) sqlmap.queryForObject("getById", new Integer(1));
??????? System.out.println("歡迎你="+emp.getName());
?}
}
-------------------------------------------------
-------------------------------------------------
-------------------------------------------------
-------------------------------------------------
-------
寫一個運行dao的
<!DOCTYPE daoConfig
PUBLIC "-//iBATIS.com//DTD DAO Configuration 2.0//EN"
"<daoConfig>
<!-- Example JDBC DAO Configuration -->
<context>
??? <transactionManager type="SQLMAP">
???? <property name="SqlMapConfigResource" value="zhai/config.xml"/>
??? </transactionManager>
<dao interface="zhai.MyDao" implementation="zhai.TestDao"/>
</context>
</daoConfig>
----------------------
--------------------
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
??? "
<sqlMap namespace="test">
? <typeAlias alias="test" type="zhai.test"/>
? <select id="getById" resultClass="test" parameterClass="int">
??? SELECT
???? ID,
???? NAME
??? FROM TEST
??? WHERE ID = #id#
? </select>
? <insert id="insertTest" parameterClass="test">
??? insert into TEST (NAME) values (#name#)
? </insert>
?
</sqlMap>
--------------------------------------------------------------------------------------------------
---------------------------------------------
package zhai;
import java.io.*;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.DaoManagerBuilder;
import com.ibatis.sqlmap.client.*;
public class TestDemo {
?public static void main(String[] args) throws Exception {
??????????????? //Reader reader = Resources.getResourceAsReader("zhai/dao.xml");
??Reader reader=new FileReader("C:\\Test\\dao.xml");
??DaoManager daoManager = DaoManagerBuilder.buildDaoManager(reader);
??MyDao testdao = (MyDao) daoManager.getDao(MyDao.class);
??test t=new test();
??t.setName("test");
??testdao.MyInsert(t);
?}
}
注意了如果你用的是
Reader reader = Resources.getResourceAsReader("zhai/dao.xml");
那么你就得注意事了,dao.xml要放在項目的bin目錄下面,否則就會出錯
還有在dao.xml里的? <transactionManager type="SQLMAP">
???? <property name="SqlMapConfigResource" value="zhai/config.xml"/>
??? </transactionManager>
也是一個道理呀