2010-06-16 66 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> 
相关问题