В недавнем проекте у меня было требование подключения к нескольким базам данных с помощью hibernate. Поскольку модуль tapestry-hibernate не обеспечивает встроенную поддержку, я подумал о добавлении одного. https://github.com/tawus/tapestry5
Теперь, когда приложение находится в производстве, я подумал написать простое «Как».
Я клонировал последний стабильный (5.3.2) проект гобелена в
https://github.com/tawus/tapestry5
и добавили поддержку нескольких баз данных к нему.
Единая база данных
Он почти полностью совместим с предыдущей интеграцией при использовании единой базы данных, за исключением нескольких вещей
1) HibernateConfigurer изменился
public interface HibernateConfigurer { /** * Passed the configuration so as to make changes. */ void configure(Configuration configuration); /** * Factory Id for which this configurer is meant for */ Class<? extends Annotation> getMarker(); /** * Entity package names * * @return */ String[] getPackageNames(); }
2) HibernateEntityPackageManager отсутствует, поскольку пакеты могут быть добавлены путем добавления большего количества HibernateConfigurers с теми же маркерами.
Несколько баз данных
Для нескольких баз данных необходимо использовать маркер для доступа к Session или HibernateSessionManager.
@Inject @XDB private Session session; @Inject @YDB private HibernateSessionManager sessionManager; @XDB @CommitAfter void myMethod(){ }
Также вы должны определить HibernateSessionManager и Session для вторичной базы данных в классе Module.
@Scope(ScopeConstants.PERTHREAD) @Marker(DatabaseTwo.class) public static HibernateSessionManager buildHibernateSessionManagerForFinacle( HibernateSessionSource sessionSource, PerthreadManager perthreadManager) { HibernateSessionManagerImpl service = new HibernateSessionManagerImpl(sessionSource, DatabaseTwo.class); perthreadManager.addThreadCleanupListener(service); return service; } @Marker(DatabaseTwo.class) public static Session buildSessionForFinacle( @Local HibernateSessionManager sessionManager, PropertyShadowBuilder propertyShadowBuilder) { return propertyShadowBuilder.build(sessionManager, "session", Session.class); }
Обратите внимание на аннотацию @ DatabaseTwo.class. Это маркер Factory и используется для идентификации службы, связанной с конкретной SessionFactory.
@Retention(RetentionPolicy.RUNTIME) @Target( {ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @FactoryMarker @Documented public @interface DatabaseTwo { }
Типичный AppModule для двух баз данных будет
public class AppModule { public static void bind(ServiceBinder binder) { binder.bind(DemoService.class, DemoServiceImpl.class); } @Contribute(HibernateSessionSource.class) public static void configureHibernateSources(OrderedConfiguration<HibernateConfigurer> configurers) { configurers.add("databaseOne", new HibernateConfigurer() { public void configure(org.hibernate.cfg.Configuration configuration) { configuration.configure("/databaseOne.xml"); } public Class<? extends Annotation> getMarker() { return DefaultFactory.class; } public String[] getPackageNames() { return new String[] {"org.example.demo.one"}; } }); configurers.add("databaseTwo", new HibernateConfigurer() { public void configure(org.hibernate.cfg.Configuration configuration) { configuration.configure("/databaseTwo.xml"); } public Class<? extends Annotation> getMarker() { return DatabaseTwo.class; } public String[] getPackageNames() { return new String[] {"org.example.demo.two"}; } }); } @Contribute(SymbolProvider.class) @ApplicationDefaults public static void addSymbols(MappedConfiguration<String, String> configuration) { configuration.add(HibernateSymbols.DEFAULT_CONFIGURATION, "false"); configuration.add("tapestry.app-package", "org.example.demo"); } @Scope(ScopeConstants.PERTHREAD) @Marker(DatabaseTwo.class) public static HibernateSessionManager buildHibernateSessionManagerForFinacle( HibernateSessionSource sessionSource, PerthreadManager perthreadManager) { HibernateSessionManagerImpl service = new HibernateSessionManagerImpl(sessionSource, DatabaseTwo.class); perthreadManager.addThreadCleanupListener(service); return service; } @Marker(DatabaseTwo.class) public static Session buildSessionForFinacle( @Local HibernateSessionManager sessionManager, PropertyShadowBuilder propertyShadowBuilder) { return propertyShadowBuilder.build(sessionManager, "session", Session.class); } }
Внедрение в Услуги
Вы можете добавить сеанс в сервис, используя маркер. Поскольку DatabaseOne используется в качестве конфигурации по умолчанию, для добавления его сеанса необходимо аннотировать его с помощью @DefaultFactory. Для DatabaseTwo вы можете использовать аннотацию @DatabaseTwo.
public class DemoServiceImpl implements DemoService { private Session sessionOne; private Session sessionTwo; public DemoServiceImpl( @DefaultFactory Session sessionOne, @DatabaseTwo Session sessionTwo) { this.sessionOne = sessionOne; this.sessionTwo = sessionTwo; } @SuppressWarnings("unchecked") public List<EntityOne> listOnes() { return sessionOne.createCriteria(EntityOne.class).list(); } @SuppressWarnings("unchecked") public List<EntityTwo> listTwos() { return sessionTwo.createCriteria(EntityTwo.class).list(); } public void save(EntityOne entityOne) { sessionOne.saveOrUpdate(entityOne); } public void save(EntityTwo entityTwo) { sessionTwo.saveOrUpdate(entityTwo); } }
Использование @CommitAfter
Вы можете добавить совет так же, как раньше. Единственное изменение в @CommitAfter. Вы должны дополнительно аннотировать метод соответствующим маркером.
public interface DemoService { List<EntityOne> listOnes(); List<EntityTwo> listTwos(); @CommitAfter @DefaultFactory void save(EntityOne entityOne); @CommitAfter @DatabaseTwo void save(EntityTwo entityTwo); }
Вот пример .
Из http://tawus.wordpress.com/2012/03/03/tapestry-hibernate-multiple-databases/