2010-06-16 2 views
3

우리는 모든 DAO에서 Spring + iBatis를 사용하여 저장 프로 시저에서 데이터를 가져옵니다.Spring + iBatis를 사용하여 내 애플 리케이션에서 디자인 문제를 해결하는 방법

두 가지 주요 JNDI 연결이 있습니다. 하나는 datawarehouse으로 가고 다른 하나는 livedb으로갑니다.

최근에 많은 SP가 라이브 버스에서 데이터웨어 하우스로 이동되었으며 그 반대의 경우도 마찬가지입니다. 이제

, 각 DAO 직접 그냥 데이터웨어 하우스 또는 livedb 하나에 관련되지 않습니다

이 때문에 자바 측에서 문제를 만드는 것입니다. DAO A에는 데이터웨어 하우스와 관련된 메소드가 있고 다른 것들은 livedb와 관련이있을 수 있습니다. 이를 위해 우리는 sqlMapClientTemplate을 변경해야합니다 (스프링은 DAO가 JNDI 연결과 일대일 매핑을하기 때문에). 그래서 우리는 이것을 다음과 같이 수행합니다 :

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

당신이 볼 수있는 것처럼 ... 이것은 많은 장소에서 같은 코드를 많이 필요로합니다.

질문

은 두 개의 서로 다른 JNDI의 한 DAO의 이야기를하기 위해 설계 결함으로 간주인가? (I 고전 JDBC의 DAO 년이 아닌 설계 결함을 알고 있지만 그것을 봄 + 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 맵을 구성-oracle.xml

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

SQL - -지도에서 config-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를 하나만 만들면됩니다. – Omnipresent

+0

@Omnipresent 왜 두 DAO를 주입합니까 (동일 할 수도 있지만) 다르게 구성합니까? –

+0

나는 당신이 무슨 뜻인지 이해하지 못했거나 그것을 어떻게하는지 잘 모릅니다. 2 개의 DAO를 주입하는 예가 있습니까? – Omnipresent

1

귀하의 정확한 어려움을 이해하는 것이 쉽지 않습니다. DAO 클래스의 골격과 다른 봄 관리 빈과의 관계를 제공하면 도움이 될 것입니다. "스프링을 사용하면 DAO가 JNDI 연결을 통해 일대일 매핑을 갖게됩니다"; 나는 그것을 얻지 못한다. Spring 컨테이너에 DataSource 빈 (각 데이터베이스 당 하나씩)과 해당하는 SqlMapClientTemplate 빈 쌍을 가질 수 있습니다. 그런 다음 각 DAO 객체에 두 개의 SqlMapClientTemplate 빈을 삽입하고 올바른 데이터베이스를 가리키는 bean을 (각 메소드에서) 사용합니다. 내가 놓친 게 있니?

는 업데이트 : 해골을보고, 나는 당신이 당신의 DAO를하는 int 주입 된 두 clientMaps을 가지고 방지 아무것도 볼, 대신 두 가지 방법을 가지고 하나 getSqlMapClientTemplate()을 갖는 : getSqlMapClientTemplateDb1()getSqlMapClientTemplateDb2() 또는 무엇이든을.

아마도 여기에는 몇 가지 개념적인 문제가 있습니다.

DAO를 인터페이스로 정의한 다음 특정 프레임 워크 또는 데이터베이스에 대한 구체적인 클래스를 구현하는 것이 일반적인 방법입니다. 목표는 인터페이스를 건드리지 않고 하나의 프레임 워크/데이터베이스에서 다른 데이터베이스로 쉽게 마이그레이션하는 것입니다. 예를 들어, public User getUser(int id) 메서드와 두 가지 구현 -sys-UserDaoPostgresqlUserDaoMysql을 사용하여 IUserDao 인터페이스를 가질 수 있습니다. 이 방법은 동일한 작업을 수행하는 두 가지 대체 방법 (대체 저장소에서 사용자를 얻는 방법)을 구현합니다. 일반적으로이 시나리오에서는 상위 레이어가이를 무시하고 사용되는 구체적인 DAO는 와이어 링 (예 : Spring)에 지정되므로 배포시 고정됩니다. 그러나 단 하나의 구현 만이 배포 된 각 인스턴스에서 사용되며 (아마도 일부 테스트 또는 마이그레이션 코드 제외) dao 내부의 코드 (위층에서도)는이 두 가지 구현에 대해 불가지론을 유지해야합니다.

그러나 다른 시나리오가 있습니다. 예를 들어, PostgreSQL 데이터베이스에 애플리케이션 데이터의 일부가 있고 Mysql db (또는 다른 독립 Pg db 또는 일부 비 관계 db, 심지어 일부 로그)에 다른 부분이있는 경우입니다. 그런 다음 DAO의 역할은 단순히 데이터 저장소에 대한 액세스를 추상화하기위한 것이므로 IUserDao에는 두 가지 메소드 getUser(int userid)getUserHistory(int userid)이있을 수 있으며 각 메소드가 다른 데이터베이스 또는 리소스에 액세스해야하는 경우가 발생할 수 있습니다. 여기에서는 하나의 DAO 클래스 내에서 명시 적으로 다른 데이터 소스를 선택하는 것은 나쁜 습관이 아닙니다.

시나리오가 전후인지를 분명히해야합니다.

+0

leon, 해골을 추가했습니다. 나는 그것이 더 좋은 생각을 줄 것이라고 생각한다. 스켈레톤에서'ExaminationIbatisDAO'가'goToDW' 메서드에서 깨질 것입니다 – Omnipresent

+0

제가 대답을 자세히 설명했습니다. – leonbloy

+0

흠, 이런 식으로해야합니까? http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch14s05.html 페이지 하단. – Omnipresent

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는 두 개의 서로 다른 livedb 데이터 소스와 동일한 유형의 하나의 콩, DW 데이터 소스 하나를 만드는 것이 좋습니다 수 있습니다 싱글과 this.Also 같은 데이터 소스를 전환은 바람직하지 것으로 보인다. 그리고 당신의 작업에 적절한 빈을 사용하십시오.

<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>