как решить проблему дизайна в моем приложении с помощью Spring + iBatis - PullRequest
3 голосов
/ 16 июня 2010

Мы используем Spring + iBatis во всех наших DAO для получения данных из хранимых процедур.

Существует два основных соединения JNDI.один идет на datawarehouse, а другой - на livedb.

В последнее время многие СП были перенесены из liveb в хранилище данных и наоборот.

Это создает проблемы на стороне java, потому что:

Теперь каждый DAO НЕ ПРОСТО напрямую связан с хранилищем данных или liveb.В DAO A могут существовать методы, относящиеся к хранилищу данных, а другие могут относиться к livingb.Чтобы сделать это, мы должны изменить sqlMapClientTemplate (потому что пружина заставляет дао иметь однозначное сопоставление с соединением 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 даосах, но отличается ли он от 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).Поэтому я получаю предложения, что у каждого дао должно быть только одно-одно сопоставление с JNDI.

Я хочу знать ... Есть ли способ обойти это вообще?

Скелет

spring-for-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-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");

Ответы [ 3 ]

1 голос
/ 23 июня 2010

Нелегко (для меня) понять вашу конкретную трудность, возможно, было бы полезно, если бы вы дали нам больше скелета вашего класса DAO и его отношений с другими бобами с пружинным управлением.Вы говорите "пружина заставляет дао иметь однозначное сопоставление с соединением JNDI" ;Я не понимаю этого.У вас наверняка может быть (в вашем контейнере Spring) пара DataSource бинов (по одному для каждой базы данных) и соответствующая пара SqlMapClientTemplate бинов.Затем вы должны внедрить в каждый объект DAO два компонента SqlMapClientTemplate и использовать (в каждом методе) тот, который указывает на правильную базу данных.Я что-то упустил?

Обновление: глядя на скелет, я не вижу ничего, что мешало бы вам вводить две clientMaps внутри вашего дао, и вместо одного getSqlMapClientTemplate() с двумя методами: getSqlMapClientTemplateDb1() getSqlMapClientTemplateDb2() или что-то еще.

Возможно, здесь есть какая-то концептуальная проблема.

Стандартная практика состоит в том, чтобы определять DAO как интерфейсы, а затем реализовывать конкретные классы для конкретной платформы или базы данных.Цель состоит в том, чтобы облегчить переход с одной платформы / базы данных на другую, не касаясь интерфейса.Так, например, вы можете иметь интерфейс IUserDao с методом public User getUser(int id) и две разные реализации -say- UserDaoPostgresql и UserDaoMysql;методы будут реализовывать два альтернативных способа сделать одно и то же (получить пользователя из альтернативных репозиториев).Как правило, в этом сценарии верхние уровни будут игнорировать это - и конкретный DAO, который будет использоваться, будет указан в проводке (например, с Spring), и, следовательно, зафиксирован во время развертывания.Но только одна реализация будет использоваться в каждом развернутом экземпляре (за исключением, возможно, некоторого кода тестирования или миграции), и код внутри dao (а также на верхних уровнях) должен оставаться независимым от этих двух альтернативных реализаций.

Но есть и другие сценарии.Например, когда одна часть данных приложения находится в базе данных Postgresql, а другая - в базе данных MySQL (или в другой независимой базе данных Pg, или в некоторой не связанной с базой данных базе данных, даже в некоторых журналах).Тогда, поскольку роль DAO состоит в том, чтобы просто абстрагировать доступ к вашим хранилищам данных, ваш IUserDao может иметь два метода getUser(int userid) getUserHistory(int userid), и вполне может случиться, что (в одной конкретной реализации) каждый метод должен иметь доступ кдругая база данных или ресурс.Здесь было бы неплохо выбирать явно разные источники данных внутри одного класса DAO.

Возможно, вам следует уточнить, является ли ваш сценарий первым или последним.

0 голосов
/ 29 июня 2010

Лучше было бы реорганизовать ваши 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 выглядят как одиночные, и не рекомендуется переключать источник данных, как этот. Также вы можете рассмотреть возможность создания двух разных bean-компонентов одного типа: один с источником данных liveb, а другой с источником данных dw И используйте соответствующий компонент для вашей задачи.

<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>
0 голосов
/ 23 июня 2010

JDBC или нет, я считаю, что Объект доступа к данным абстрагирует одну базовую реализацию доступа к данным. Поэтому, даже если они используют один и тот же интерфейс, я бы предоставил две реализации, если у меня есть два источника данных (независимо от того, являются ли они двумя СУБД или нет).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...