2010-06-16 64 views
3

我們在所有DAO中使用Spring + iBatis從存儲過程中獲取數據。如何使用Spring + iBatis解決我應用程序中的設計問題

有兩個主要的JNDI連接。一個去datawarehouse,另一個去livedb

最近很多SP已經從livedb移動到數據倉庫,反之亦然。

這是在Java端創建的問題,因爲:

現在,每個DAO並不直接涉及JUST要麼數據倉庫或livedb。 DAO A中可能存在與數據倉庫相關的方法,而其他方法可能與livedb相關。爲了做到這一點,我們必須更改sqlMapClientTemplate(因爲spring使得dao與JNDI連接有一對一映射)。所以我們這樣做:

this.setSqlMapClientTemplate(getSqlTemplDW()); //get connection to DW 
getSqlMapClientTemplate().queryForList("dw_sps.somemapping", parmMap); 
this.setSqlMapClientTemplate(getSqlTempl()); //set connection to live db 

正如你所看到的......這迫使我們在一堆地方有很多相同的代碼。

問題

是它被認爲是設計缺陷有一個DAO聊到兩個不同的JNDI的? (我知道它不是在傳統的JDBC DAOS一個設計缺陷,但它與Spring + iBatis的不同?)你看那裏

的getSqlTemplDW()方法如下所示:

public SqlMapClientTemplate getSqlTemplDW() { 
    SqlMapClient scl = (SqlMapClient) ApplicationInitializer.getApplicationContext().getBean("SqlMapClientDW"); 
    DataSource dsc = (DataSource) ApplicationInitializer.getApplicationContext().getBean("DataSourceDW"); 
    return new SqlMapClientTemplate(dsc, scl); 
} 

,你可以看到,我正在使用javax.sql.DataSource。但是,我們被告知不要使用這種進口!所以現在我被卡住了。我不能使用此導入(意思是不能改變我的DAO連接)。所以我一直在建議每個dao應該只有一對一映射到JNDI。

我想知道..有沒有解決這個問題的方法呢?

骨架

彈簧換ibatis.xml

<bean id="datasource1" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="jdbc/RSRC/asdf/sdf/oltp"/> 
</bean> 

<bean id="datasource2" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="jdbc/RSRC/asdf/efs/dw"/> 
</bean> 

<bean id="sqlMapClient1" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
    <property name="configLocation" value="classpath:sql-map-config-oracle.xml"/> 
    <property name="dataSource" ref="datasource1"/> 
</bean> 

<bean id="sqlMapClient2" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
    <property name="configLocation" value="classpath:sql-map-config-dw.xml"/> 
    <property name="dataSource" ref="datasource2"/> 
</bean> 

<!--dao bean--> 
<bean id="examinationIfaceDAO" class="some.path.ExaminationIbatisDAO"> 
    <property name="sqlMapClient" ref="sqlMapClient1"/> 
    <property name="dataSource" ref="datasource1"/> 
</bean> 

SQL-MAP-CONFIG-oracle.xml

<sqlMapConfig> 
    <settings enhancementEnabled="true" useStatementNamespaces="true" /> 
     <sqlMap resource="iBatis_file_with_sps_to_live_db.xml"/> 
</sqlMapConfig> 

SQL-MAP-配置-DW。爲檢驗XML

<sqlMapConfig> 
    <settings enhancementEnabled="true" useStatementNamespaces="true" /> 
    <sqlMap resource="iBatis_file_with_sps_to_dw.xml" /> 
</sqlMapConfig> 

接口

public interface ExaminationIfaceDAO { 
    public boolean goToDW(String userId); 
    public boolean goToLiveDB(String userId); 
} 

ExaminationIbatisDAO

public class ExaminationIbatisDAO implements EexaminationIfaceDAO { 
    public boolean goToDW(String userId) { 
     HashMap paramMap = new HashMap(); 
     paramMap.put("userId", userId); 
     //following line will break as it does not know about this mapping file 
     getSqlMapClientTemplate().queryForObject("iBatis_file_with_sps_to_dw.isAuthorized", paramMap); 
     return true; 
    } 
    public boolean goToLiveDB(String userId) { 
     HashMap paramMap = new HashMap(); 
     paramMap.put("userId", userId); 
     //following line will be ok as it knows about this mapping file 
     getSqlMapClientTemplate().queryForObject("iBatis_file_with_sps_to_live_db.isAuthorized", paramMap); 
     return true; 
    } 
} 

調用這一切都源自一些行動

examDAO = (ExaminationIfaceDAO)ApplicationInitializer.getApplicationContext().getBean("eexaminationIfaceDAO"); 
boolean b = reexamDAO.goToDW("myuserid"); 

回答

0

JDBC與否,我認爲Data Access Object抽象了一個底層的數據訪問實現。因此,即使它們共享相同的接口,如果我有兩個數據源(無論它們是否是兩個RDBMS),我也會提供兩個實現。

+0

我確信DAO應該抽象一個數據訪問。然而,目前可能是我的解決方案,以擺脫在一堆地方的所有相同的代碼。使每個DAO只有一個jndi現在是我們的巨大努力 – Omnipresent 2010-06-23 15:55:46

+0

@Omnipresent爲什麼不注入兩個DAO(可能是相同的),但配置不同? – 2010-06-23 16:00:44

+0

我不確定我是否理解你的意思,或者我不知道如何去做。有一個例子,我可以看到注入兩個DAO的? – Omnipresent 2010-06-23 16:05:53

1

要理解你的確切難度並不容易,如果你給我們更多的DAO類的骨架以及它與其他春季管理的bean的關係,它可能會有所幫助。 你可以說「春季做了一個有JNDI連接的映射」;我不明白。你當然可以(在你的Spring容器中)有一對DataSource bean(每個數據庫一個)和一個相應的對SqlMapClientTemplate bean。然後你可以在每個DAO對象中注入兩個SqlMapClientTemplate bean,並使用(在每種方法中)指向正確數據庫的那個。我錯過了什麼嗎?

更新:看着骷髏,我什麼也看不見,防止你有注入INT您的DAO兩個clientMaps,和而不必有以下兩種方法之一getSqlMapClientTemplate()getSqlMapClientTemplateDb1()getSqlMapClientTemplateDb2()或什麼的。

也許這裏有一些概念問題。

一個標準的做法是將DAO定義爲接口,然後實現特定框架或數據庫的具體類。目標是減輕從一個框架/數據庫到另一個框架的遷移,而不會觸及界面。因此,例如,您可以使用方法public User getUser(int id)的IUserDao接口,以及兩種不同的實現方式 - 即 - UserDaoPostgresqlUserDaoMysql;這些方法將實現兩種做同樣事情的替代方式(從備選存儲庫中獲取用戶)。通常情況下,在這種情況下,上層將忽略這一點 - 並且要使用的具體DAO將在接線中指定(例如,使用Spring),並因此在部署時進行修復。但是每個部署的實例中只會使用一個實現(除了可能在某些測試或遷移代碼中),並且dao(以及上層)中的代碼應該對這兩個替代實現保持不可知論。

但還有其他場景。例如,當一個應用程序數據在Postgresql數據庫中,另一個部分在Mysql數據庫(或另一個獨立的Pg數據庫,或者在一些非關係數據庫,甚至一些日誌中)時。然後,由於DAO的作用僅僅是將訪問摘要提取到數據存儲庫,因此您的IUserDao可能有兩種方法,它們可能完全發生(在一個特定實現中),每種方法都必須訪問不同的數據庫或資源。在這裏,在一個DAO類中選擇明確不同的數據源並不是壞習慣。

也許你應該清楚,如果你的情況是前者或後者。

+0

leon,我添加了一個骷髏。我認爲這會給出更好的想法。從骨架上看,'ExamIbatisDAO'將在'goToDW'方法上破解 – Omnipresent 2010-06-23 23:12:57

+0

我詳細闡述了我的答案。 – leonbloy 2010-06-24 14:01:04

+0

嗯,我應該做這樣的事情嗎? http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch14s05.html頁面底部。 – Omnipresent 2010-06-25 04:31:17

0

更好的設計是重構你的DAO。像這樣的東西。

public interface ExaminationIfaceDAO { 
    boolean checkUser(String userId); 
} 

public class OracleExaminationDAO implements ExaminationIfaceDAO{ 
    public boolean checkUser(String userId){ 
     //TO:DO 
    } 
} 
public class DWExaminationDAO implements ExaminationIfaceDAO{ 
    public boolean checkUser(String userId){ 
     //TO:DO 
    } 
} 

你的DAO看起來是單身人士和其不可取的切換數據源像this.Also你可以考慮創建同一類型的一個與livedb數據源兩個不同的豆類和一個用DW數據源。併爲您的任務使用適當的bean。

<bean id="examinationDBDAO" class="some.path.ExaminationIbatisDAO"> 
<property name="sqlMapClient" ref="sqlMapClient1"/> 
<property name="dataSource" ref="datasource1"/> 
</bean> 
<bean id="examinationDWDAO" class="some.path.ExaminationIbatisDAO"> 
<property name="sqlMapClient" ref="sqlMapClient1"/> 
<property name="dataSource" ref="datasource2"/> 
</bean> 
相關問題