2012-11-26 14 views
5

Ho un'applicazione Java che utilizza Spring/Hibernate (in esecuzione su Amazon Elastic Beanstalk) con un'istanza di Amazon RDS normale. Per distribuire il carico, aggiungo una replica di lettura. Ho scambiato il DB.url con la replica di lettura e ho testato un metodo che dovrebbe leggere solo i dati (i metodi non utilizzano sicuramente UPDATE, INSERT o DELETE). L'applicazione, tuttavia, restituisce errori.Come configurare Spring/Hibernate con MySQL Read-Replica

Le mie domande: Perché l'applicazione non funziona quando si leggono solo i dati? Come posso configurare Spring/Hibernate affinché funzioni con una replica di lettura?

I Dettagli:

L'errore che sto ottenendo è:

INFO: Internal error in method IEngageManager.getSimpleExamActivityLiveResults, ARGUMENTS=[ 
    Credentials { 
(m) password=0c2a765c057a31c51b68d0f6c75cef93, 
(m) email=w1jg 
    } 
] 
com.iengage.exceptions.IEException: Internal error in method IEngageManager.getSimpleExamActivityLiveResults, ARGUMENTS=[ 
    Credentials { 
    (m) password=0c2a765c057a31c51b68d0f6c75cef93, 
    (m) email=w1jg 
    } 
] 
    at com.iengage.exceptions.ExceptionWrapper.overridingInvoke(ExceptionWrapper.java:25) 
    at com.iengage.springobjects.SingletonMethodInterceptor.invoke(SingletonMethodInterceptor.java:18) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621) 
    at com.iengage.managers.IEngageManager$$EnhancerByCGLIB$$c8a2c385.getSimpleExamActivityLiveResults(<generated>) 
    at com.iengage.services.IEngageService.getSimpleExamActivityLiveResults(IEngageService.java:379) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:616) 
    at com.sun.xml.ws.api.server.InstanceResolver$1.invoke(InstanceResolver.java:246) 
    at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:146) 
    at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:257) 
    at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:93) 
    at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:595) 
    at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:554) 
    at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:539) 
    at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:436) 
    at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:243) 
    at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:444) 
    at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244) 
    at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:135) 
    at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:129) 
    at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doPost(WSServletDelegate.java:160) 
    at com.sun.xml.ws.transport.http.servlet.WSSpringServlet.doPost(WSSpringServlet.java:52) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) 
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:680) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999) 
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
    at java.lang.Thread.run(Thread.java:679) 

Il codice che chiama il DB:

public LecturerBO getLecturerByCode(Credentials credentials) { 
    return findSingleResultByCriteria(LecturerBO.class,Restrictions.eq("loginCode",credentials.getPassword())); 
} 

dove

protected <T> T findSingleResultByCriteria(Class<T> clazz, Criterion... criterion) { 
    Criteria crit = getSession().createCriteria(clazz); 
    for (Criterion c : criterion) { 
     crit.add(c); 
    } 
    return (T) crit.uniqueResult(); 
} 

E per ultimo, la configurazione di Hibernate:

<bean id="generalManagerProxyTemplate" 
     class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
     abstract="true"> 
    <property name="transactionManager" ref="hibernateTransactionManager"/> 
    <property name="proxyTargetClass" value="true"/> 
    <property name="transactionAttributes"> 
     <props> 
      <prop key="*">PROPAGATION_REQUIRED</prop> 
     </props> 
    </property> 
    <property name="preInterceptors"> 
     <list> 
      <bean class="com.iengage.exceptions.ExceptionWrapper"/> 
      <bean class="com.iengage.utils.PerformanceLogger"/> 
     </list> 
    </property> 
</bean> 

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory"/> 
</bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="dataSource" ref="pooledDataSource"/> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> 
      <prop key="transaction.auto_close_session">true</prop> 
      <prop key="transaction.flush_before_completion">true</prop> 
      <prop key="show_sql">false</prop> 
      <prop key="hibernate.cache.use_query_cache">false</prop> 
      <prop key="hibernate.show_sql">false</prop> 
     </props> 
    </property> 
    <property name="annotatedClasses"> 
     <bean class="com.iengage.dao.EntityList"/> 
    </property> 
</bean> 

<bean id="pooledDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="driverClassName" value="${db.driverClassName}"/> 
    <property name="url" value="${db.url}"/> 
    <property name="username" value="${db.username}"/> 
    <property name="password" value="${db.password}"/> 
    <property name="defaultAutoCommit" value="false"/> 
    <property name="testWhileIdle" value="true"/> 
</bean> 

<bean id="abstractDAO" class="com.iengage.dao.GeneralDAO" abstract="true"> 
    <property name="sessionFactory" ref="sessionFactory"/> 
    <property name="dataSource" ref="pooledDataSource"/> 
</bean> 

<bean id="dao" class="com.iengage.dao.IEngageDAO" parent="abstractDAO"/> 

E per ultimo, come un controllo di integrità, mi collego con la lettura replica direttamente e tramite un semplice script che esegue le query SELECT che ho ospitato su un server di terze parti . Tutto ha funzionato come previsto.

Inoltre, nella mia ricerca prima di pubblicare questa domanda, la maggior parte delle risposte si concentrava sull'annotazione @Transactional, che non viene utilizzata. Panda triste

Grazie per qualsiasi aiuto.

+0

Stai omettendo la causa dell'eccezione generata? (ad esempio lanciando una nuova IEException senza il solito argomento gettabile?) – Vincent

risposta

1

Per fornire questo tipo di accesso (solo Read-Replica) è necessario implementare questa proprietà.

 <property name="transactionAttributes"> 
      <props> 
       <prop key="get*">PROPAGATION_REQUIRED,readOnly 
       </prop> 
       <prop key="find*">PROPAGATION_REQUIRED,readOnly 
       </prop> 
       <prop key="load*">PROPAGATION_REQUIRED,readOnly 
       </prop> 
       <prop key="store*">PROPAGATION_REQUIRED</prop> 
       <prop key="add*">PROPAGATION_REQUIRED</prop> 
      </props> 
     </property> 

qui, io uso questo due per consentire di memorizzare e aggiungere in DB. devi rimuovere questo se non hai bisogno.

 <prop key="store*">PROPAGATION_REQUIRED</prop> 
     <prop key="add*">PROPAGATION_REQUIRED</prop> 
Problemi correlati