В недавнем проекте у меня было требование подключения к нескольким базам данных с помощью 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/