问题
I am working on a Spring-MVC application in which as of now we had a single data source. For our requirements, where most of the transactions are either short lived, we do have applications which rarely require very long time to process. To avoid the system being choked up because of those requests, we are planning to create a separate data source.
Other than that, those methods will have a lower priority, as user knows these will take a longer time. For that, I am simply calling Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
. Is this sufficient? The main point is, these methods should not consume more time on CPU, disk, I/O, etc.
Like other spring-mvc applications, we have 3 layers, controller, service, DAO. Some of the service layer methods will be shared amongst these data-sources. Example : long_method_service_layer()-->dependent_method_service_layer()
. Also short_method_service_layer()-->dependent_method_service_layer();
So now when the 2nd datasource calls the dependent_method(), will it also have a low priority?
Currently, our service layer is configured this way :
@Service
@Transactional
public class DownloadTokenServiceImpl implements DownloadTokenService{
private final DownloadTokenDAO downloadTokenDAO;
@Autowired
public DownloadTokenServiceImpl(DownloadTokenDAO downloadTokenDAO){
this.downloadTokenDAO = downloadTokenDAO;
}
@Override
public void method_name(){}
}
The methods from 2nd datasource will also be inside this class. I am planning to annotate those methods separately with @Transactional("2nd_source")
. Is this correct?
Finally, Error log from my attempt as of now :
Caused by:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: hibernate4AnnotatedSessionFactory_extended,hibernate4AnnotatedSessionFactory
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1133)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1021)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:814)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
at org.s
root-context.xml :
1st data_source (Primary) :
<beans:bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<beans:property name="dataSourceClassName" value="org.postgresql.ds.PGSimpleDataSource"/>
<beans:property name="maximumPoolSize" value="50" />
<beans:property name="maxLifetime" value="200000" />
<beans:property name="idleTimeout" value="25000" />
<beans:property name="leakDetectionThreshold" value="200000"/>
<beans:property name="connectionTimeout" value="200000"/>
<beans:property name="dataSourceProperties">
<beans:props>
<beans:prop key="url">jdbc:postgresql://localhost:5432/DB_NAME</beans:prop>
<beans:prop key="user">username</beans:prop>
<beans:prop key="password">password</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="packagesToScan" value="com.our_app.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.jdbc.batch_size">50</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="cache.use_second_level_cache">true</beans:prop>
<beans:prop key="cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<beans:prop key="show_sql">false</beans:prop>
<beans:prop key="connection.release_mode">after_statement</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/>
</beans:bean>
2nd datasource(required for long running transactions, hikari values to be adjusted once its working) :
<beans:bean id="extended_transactions_data_source" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<beans:property name="dataSourceClassName" value="org.postgresql.ds.PGSimpleDataSource"/>
<beans:property name="maximumPoolSize" value="50" />
<beans:property name="maxLifetime" value="200000" />
<beans:property name="idleTimeout" value="25000" />
<beans:property name="leakDetectionThreshold" value="200000"/>
<beans:property name="connectionTimeout" value="200000"/>
<beans:property name="dataSourceProperties">
<beans:props>
<beans:prop key="url">jdbc:postgresql://localhost:5432/Db_NAME</beans:prop>
<beans:prop key="user">USERNAME</beans:prop>
<beans:prop key="password">passwoRD</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<beans:bean id="hibernate4AnnotatedSessionFactory_extended"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="extended_transactions_data_source"/>
<beans:property name="packagesToScan" value="com.our_app.spring.model"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.jdbc.batch_size">50</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="cache.use_second_level_cache">true</beans:prop>
<beans:prop key="cache.use_query_cache">true</beans:prop>
<beans:prop key="hibernate.order_updates">true</beans:prop>
<beans:prop key="show_sql">false</beans:prop>
<beans:prop key="connection.release_mode">after_statement</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager_extended"/>
<beans:bean id="transactionManager_extended" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory_extended"/>
</beans:bean>
回答1:
I don't think this is an exact duplicate of this post, but it's got some strong similarities. Take a look at the accepted answer there and note that, in the DAO, they're autowiring both session factories. The author is also using the Qualifier annotation to keep separate. In your DAO, you may want to do something like:
@Autowired
@Qualifier(value="hibernate4AnnotatedSessionFactory")
private SessionFactory hibernate4AnnotatedSessionFactory;
@Autowired
@Qualifier(value="hibernate4AnnotatedSessionFactory_extended")
private SessionFactory hibernate4AnnotatedSessionFactory_extended;
I think in this case, you wouldn't have to qualify the Transactional annotations, since your DAO implementation will have to explicitly use one session factory or the other.
来源:https://stackoverflow.com/questions/50509420/java-spring-create-a-separate-datasource-bean-throws-nonunique-error