天天看點

IBATIS 源碼解讀--DataAccess

DataAccess是一個DAO架構,可以通過配置檔案配置應用程式使用的DAO實作,并且自己提供了幾個具體資料通路方式的包裝,以簡化DAO實作層開發。

DataAccess的源代碼相對于DataMapper要簡單的多。

一.關鍵類

1.Configuration目錄

定義了DataAccess的模型,該模型和xml配置檔案對應,是以該目錄同時提供了從xml配置檔案解析為DataAccess對象模型和将對象模型序列化為xml檔案的功能。

2.Exceptions目錄

Exceptions目錄中隻有一個DataAccessException異常類。DataAccess架構産生的異常會被包裝為該類。

3.Interfaces目錄

Interfaces目錄定義了兩個接口:IDao和IDaoSessionHandler。IDao是我們自己的DAO實作類必須繼承的标志接口。IDaoSessionHandler定義了不同會話處理器(SessionHandler)的通用接口。用于從配置Dao管理器相關的資訊,并擷取目前的DaoSession。

4.Scope目錄

維護目前的配置和錯誤資訊。

5.DaoSessionHandlers目錄

DaoSessionHandlers目錄包含對ADO.NET和SqlMap的包裝。比如SimpleDaoSession 是 An ADO.NET implementation of the DataAccess Session .SqlMapDaoSession 是 An SqlMappper implementation of the DataAccess Session.這兩個類都實作了IDaoSession,用來處理會話相關的連接配接,事務等。SimpleDaoSessionHandler和SqlMapDaoSessionHandler類都實作了IDaoSessionHandler接口,用于從解析後的配置資訊中擷取DaoSession和其相關的配置。

6.主目錄

SessionHolder類和java中的ThreadLocal類似,為每個線程維護一個IDalSession。

DaoManager是一個Facade類,複雜讀取配置檔案并初始化架構;為不同的context維護不同的配置資訊;提供通路DAO實作的方法;提供通路目前Session中的連接配接(connection)和事務(transaction)方法。

二.使用簡介和架構執行流程

DataAccess架構(圖略):

由于DataAccess可以和任何DAO實作工作,核心庫中提供了對ADO.NET和SqlMap(也就是DataMapper)的封裝,擴充庫中提供了對NHibernate的封裝,利用這些封裝編成很更簡單,更實用。DataAccess文檔上說:

if your application is using raw ADO, the DAO framework will hide classes like DataReader, DataAdapter, Connection, and Command. Similarly, if your application is using the NHibernate object persistence library, the DAO framework will hide classes like Configuration, SessionFactory, Session, and HibernateException. All of these implementation details will be hidden behind a consistent DAO interface layer. Furthermore, the number of different data sources that are being used can be hidden from the view of the application.

這裡隻簡單介紹DataAccess和DataMapper配合使用,DataMapper的類和配置利用以上介紹的DataMapper中的例子。

DataAccess的使用需要以下幾個步驟:

1.設計DAO接口。

2.選擇一種DAO實作。

3.編寫dao.config配置檔案。

4.利用DAO進行資料操作。

由于DataAccess架構要求每個DAO實作類,必須實作IDao接口,即然利用DAO架構程式設計,我們必須定義自己的DAO接口。作為最佳實踐可以這樣設計:

1).我們自己的DAO接口應該是和任何架構無關的,也就是我們的DAO接口不需要繼承自IDao接口,而且所有的DAO接口在一個或幾個項目中,最後打包為一個或幾個dll中,例如:

namespace dao

{

public interface IProduct

{

IList GetProductList();

void UpdateProduct(Product pro);

}

}

2).設計一個BaseDao基類,該類封裝了一種具體的DAO實作的資料通路方法并且實作IDao标志接口,例如我們利用SqlMapper作為資料持久層,BaseDao可以這樣設計:

namespace impl

{

public class BaseDao : IDao

{

protected const int PAGE_SIZE = 4;

///

/// Looks up the parent DaoManager, gets the local transaction

/// (which should be a SqlMapDaoTransaction) and returns the

/// SqlMap associated with this DAO.

///

/// The SqlMap instance for this DAO.

protected SqlMapper GetLocalSqlMap()

{

DomDaoManagerBuilder builder = new DomDaoManagerBuilder();

builder.Configure();

DaoManager daoManager = DaoManager.GetInstance(this);

SqlMapDaoSession sqlMapDaoSession = (SqlMapDaoSession)daoManager.LocalDaoSession;

return sqlMapDaoSession.SqlMap;

}

///

/// Simple convenience method to wrap the SqlMap method of the same name.

/// Wraps the exception with a DataAccessException to isolate the SqlMap framework.

///

///

///

///

protected IList ExecuteQueryForList(string statementName, object parameterObject)

{

SqlMapper sqlMap = GetLocalSqlMap();

try

{

return sqlMap.QueryForList(statementName, parameterObject);

}

catch (Exception e)

{

throw new DataAccessException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e);

}

}

///

/// Simple convenience method to wrap the SqlMap method of the same name.

/// Wraps the exception with a DataAccessException to isolate the SqlMap framework.

///

///

///

///

///

///

protected IList ExecuteQueryForList(string statementName, object parameterObject, int skipResults, int maxResults)

{

SqlMapper sqlMap = GetLocalSqlMap();

try

{

return sqlMap.QueryForList(statementName, parameterObject, skipResults, maxResults);

}

catch (Exception e)

{

throw new DataAccessException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e);

}

}

...................

}

}

3).我們的具體DAO實作類繼承自BaseDao,并實作自己的DAO接口。并利用BaseDao提供的基礎功能工作,而且所有的DAO實作在一個或幾個項目中,最後打包為一個或幾個dll中,這樣以後可以簡化維護并友善修改daofactory的配置,例如:

namespace impl

{

public class ProductDAO : BaseDao, IProduct

{

#region IProduct Members

public IList GetTheProductList()

{

IList prods = base.ExecuteQueryForList("getProduct", null);

Console.WriteLine("public System.Collections.IList GetProductList():");

foreach (Product p in prods)

{

Console.WriteLine("id:{0};Org:{1};PlatId:{2}", p.Id, p.Org, p.PlatId);

}

return prods;

}

public void UpdateTheProduct(Product pro)

{

base.ExecuteUpdate("updateNews", pro);

Console.WriteLine("public void UpdateProduct(Domain.Product pro) finished.");

}

#endregion

}

}

配置檔案--dao.config

xml version="1.0" encoding="utf-8"?>

<daoConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >

<providers resource="providers.config"/>

<context id="SqlMapDao" default="true">

<database>

<provider name="oracle9.2"/>

<dataSource name="ibatisDemo" connectionString="Data Source=DATA-89;Persist Security Info=True;User ID=data;password=data"/>

database>

<daoSessionHandlers>

<daoSessionHandler id="SqlMap">

<property name="resource" value="sqlMap.config"/>

daoSessionHandler>

daoSessionHandlers>

<daoFactory>

<dao inter implementation="impl.ProductDAO,impl"/>

daoFactory>

context>

daoConfig>

使用DAO實作操作資料存儲

namespace OraTest

{

class Program

{

public static void Main()

{

public static void Main()

{

//讀取配置檔案建立DaoManager,并擷取SqlMapDao context執行個體。

DomDaoManagerBuilder builder = new DomDaoManagerBuilder();

builder.Configure();

DaoManager daoManager = DaoManager.GetInstance("SqlMapDao");

//擷取IProductDAO接口的具體實作類,并初始化。

IProduct dao = daoManager[typeof(IProduct)] as IProduct;

//利用DAO程式設計。

dao.GetProductList();

Product p = new Product();

p.Id = "FR20T0000003000000096426";

p.Org = "orgid2";

dao.UpdateProduct(p);

}

}

}