2009-02-17 8 views
5

Приложение, в котором я работаю, имеет один класс, поддерживающий соединение с базой данных. Все члены этого класса являются статическими для обеспечения одноэлементного-подобный рисунка, поэтому фактическая логика соединения выполняются в статическом блоке инициализации:Каков наилучший способ дублирования/расширения функциональности статического класса?

public class HibernateUtil { 

    private static final SessionFactory sessionFactory; 

    static { 
     sessionFactory = new Configuration().configure().buildSessionFactory(); 
    } 

    static void openSession() { 
     //open session with sessionFactory 
    } 

    public static Session currentSession() { 
     //return the currently open session 
    } 

    static void closeSession() { 
     //close the currently open session 
    } 

} 

Однако приложение теперь необходимо открыть соединение с базой данных на вторую базу , Теперь, когда этот класс структурирован, единственный способ сохранить второе соединение, сохранив вышеуказанный шаблон, - создать второй класс (что-то вроде SecondHibernateUtil) и изменить одну строку конфигурации в блоке инициализатора. Это похоже на действительно расточительное количество копий/пасты.

Может ли кто-нибудь предложить способ, которым я мог бы переработать эту настройку для одновременного поддержания нескольких соединений, не будучи слишком разрушительным для кода, уже вызывающего существующие методы?

ответ

2

Сохраните статические методы и позвольте им делегировать соответствующие методы экземпляра экземпляра по умолчанию.

Для вторичных баз данных можно создавать дополнительные экземпляры любыми способами и получать доступ к ним через их методы экземпляра.

Затем вы можете отладить у вызывающих статических методов, а когда все они ушли, удалите статические методы.

2

Возможно, он не должен был быть статичным в первую очередь.

+1

Согласовано. Сделайте класс нестатическим и добавьте статический заводский метод для возврата нового экземпляра. –

+0

Я думал о длинном ответе, но это в значительной степени подводит итог. – eljenso

+0

Это не ответ, а комментарий. – OscarRyz

0

Существует не очень хороший способ, иногда нет никакого другого выбора, кроме как просто копировать всю продажу класса и жить с дублированием.

Я знаю, это звучит действительно bad, но черт возьми, сколько раз этот класс фактически изменился с тех пор, как он был скопирован из документации гибернации?

Я уверен, что кто-то собирается приступить к преобразованию всего приложения, чтобы весна управлялась SessionFactory и все это, но если ваше приложение не спящий «Hello World», тогда я бы предположил, что это может занять немного больше времени, чем Пару часов.

+0

«нет реального выбора» - я думаю, что есть. Этот класс не должен быть статическим. «копировать весь класс продажи» не СУХОЙ. – duffymo

+0

как я уже говорил * иногда * нет выбора ... если это так, что сделать это не статичным, это рефакторинг половины вашего приложения, а в реальном мире действительно не так много выбора. –

0

Узнать Весна. Если вы уже используете Hibernate, это не будет растянуть, чтобы выучить достаточно Spring, чтобы справиться с этой проблемой. Люди из Spring Source уже решили эту проблему лучше, чем когда-либо.

Весенние транзакции действительны для JDBC, Hibernate, iBatis или любой другой технологии персистентности, поддерживаемой Spring. Если вы уже используете Spring, не изобретайте то, что они уже сделали лучше. Используйте свои транзакции.

Если у вас несколько баз данных, и вы выполняете запись как в единое целое, вы знаете достаточно, чтобы использовать драйверы XA для обоих, верно?

0

Существует два возможных ответа; давайте посмотрим на оба.

Одним из них является преобразование его в нестатический. Возможно, это было бы лучше, чем статический интерфейс, в первую очередь, поскольку у вас есть конкретный объект (SessionFactory) за интерфейсом. Преимущество этого заключается в том, что вы откладываете создание SessionFactory, пока оно вам не понадобится (и никогда не создавайте его, если вы этого не сделаете). Создайте статический метод для получения объекта HibernateUtil по умолчанию, создав его, если он не существует. Вы можете или не хотите разрешать второй HibernateUtil.

Другой способ - создать совершенно новый статический объект HibernateUtil2, который в случае необходимости делегирует HibernateUtil. Однако обратите внимание, что они не будут связаны друг с другом каким-либо образом наследования, потому что статика не может использоваться в интерфейсах.

Я бы порекомендовал первый маршрут, при прочих равных условиях, но ваш конкретный случай может потребовать второй.

1

Ну, это подходящее время, чтобы сделать все правильно.

Невозможно добавить второе соединение и сохранить шаблон, который вы описали.

Вместо этого вы можете попытаться все исправить.

У вас есть два варианта.

Первый вариант. Держите беспорядок и сделайте его немного худшим (не сообщая вашим клиентам)

  1. Создайте класс утилиты, который обрабатывает соединения для вас. На этот раз не ограничиваются только двумя. Вместо этого используйте карту и не ставьте ее.
  2. Измените свой статический класс на использование нового объекта утилиты.
  3. Создайте свою новую утилиту подключения (HibernateUtility2) и используйте этот новый объект утилиты.

    // Create a new utility class using a map instead. 
    class HibernateUtility { 
    
        private Map<String, SessionFactory> factories; 
        private HibernateUtility instance; 
    
        public static HibernateUtility getInstance() { 
         if(instance == null) { 
         instance = new HibernateUtility(); 
         } 
         return instance; 
        } 
    
        private HibernateUtility() {} 
    
        private void check(String whichConnection) { 
         if(!factories.containsKey(whichConnection)) { 
          // start the connection 
          factories.put(whichConnection, new Configu.. 
          //... etc etc().configure().buildSessionFactory()); 
         } 
        } 
    
        void openSession(String whichConnection) { 
         check(whichConnection); 
         //open session with sessionFactory 
         factories.get(whichConnection).open(); //etcetc 
        } 
    
        Session currentSession(whichConnection) { 
         check(whichConnection); 
         //return the currently open session 
         factories.get(whichConnection) ..... 
        } 
    
        void closeSession(String whichConnection) { 
         check(whichConnection); 
         //close the currently open session 
         factories.get(whichConnection); 
        }  
    } 
    
    //------------------------------------------ 
    // Make your existing class call that class 
    public class HibernateUtil { 
    
        static void openSession() { 
         //open session with sessionFactory 
         HibernateUtility.getInstance("one").openSession(); 
        } 
    
        public static Session currentSession() { 
         //return the currently open session 
         HibernateUtility.getInstance("one").currentSession(); 
        } 
    
        static void closeSession() { 
         //close the currently open session 
         HibernateUtility.getInstance("one").closeSession(); 
        } 
    } 
    
    //------------------------------------------    
    // Make the new connection use that class too. 
    public class HibernateUtil { 
    
        static void openSession() { 
         //open session with sessionFactory 
         HibernateUtility.getInstance("two").openSession(); 
        } 
    
        public static Session currentSession() { 
         //return the currently open session 
         HibernateUtility.getInstance("two").currentSession(); 
        } 
    
        static void closeSession() { 
         //close the currently open session 
         HibernateUtility.getInstance("two").closeSession(); 
        } 
    } 
    

Таким образом, существующий клиентский код не будет ломаться.

Второй вариант. Очистите беспорядок и соответствующим образом измените код.

В этом втором варианте вы создаете объект, очень похожий на HibernateUtility описано выше, но на этот раз вы не добавите методы openSession ни closeSession, которые не принадлежат к этому интерфейсу.

Используя этот нестатический метод, давайте создадим разные экземпляры, которые могут подключаться к различным конфигурациям.

Вы просто просто использовать currentSession, что если сеанс не существует, создает новый, и получить в качестве параметра идентификатор (так же, как «один» и «два» в предыдущем примере)

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

Примечание: Somethings неправильно с форматирования кода в SO, мне потребовалось некоторое время, чтобы отформатировать его так, как она есть, и это не выглядит хорошо :(

+0

@duffymo: Я хотел выразить клиентский код, не останавливаясь, не сломается. :) :) :) naahhh просто шучу: «Спасибо за редактирование! ... – OscarRyz

1

Я посмотрел на этот вопрос давным-давно, и из-за точного вопроса, который вы задаете, я решил никогда не создавать статические классы, как это. На самом деле есть две проблемы с этим ...

Сначала он не может использоваться повторно (как вы заметили) и фиксирует его жесткий рефактор.

Во-вторых, вы не можете иметь второй экземпляр (Похоже, программисты предположить, что существует только одна из вещей почти так же, как они предполагают, что они никогда не должны изменить первые две цифры даты!)

Если вы решите, что хотите получить второй экземпляр с заводским шаблоном (или что-то вроде пружины), это тривиальное изменение - просто передайте переменную на фабрику, чтобы указать, какой экземпляр вам нужен, но для рефакторинга из статического класса просто сука.

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

0

Наименее разрушительным способом исправить это было бы добавление второй статической переменной в класс, инициализация 2-го SessionFactory в статическом блоке, а затем изменение статического метода «currentSession», чтобы параметр String выбирал правильный экземпляр на основе вашего бизнеса/кодовая логика.

0

Я не знаю общего решения этой проблемы, но здесь вы можете объявить нестатические SessionFactory s и установить конфигурации в своем коде, а не в свой файл hibernate.cfg.xml! поэтому у вас может быть более одного SessionFactory для подключения к нескольким базам данных для более разных сопоставлений.