mardi 24 février 2015

Could not obtain transaction-synchronized Session for current thread - SQL Server read-only table view

I am in the process of migrating a JBoss web application to Tomcat. During that migration I shifted to using Spring to configure Hibernate Session Factories and their respective data sources. When I began trying to hit the databases it complained about transactions, so I added declarative transaction management.


The problem I am having is that transaction management is working for one data source and not the other. Originally I thought the problem had to do with multiple data source / session factory / transaction manager groups; but removing all but the problematic group still didn't work.


The only thing unique about the data source which doesn't work is that it is a SQL Server "table view". In JBoss, the data source was configured as a no-tx-datasource but then still referred to the TransactionManager service:



<session-factory name="java:/hibernate/HibernateLoggingFactory" bean="jboss.har:service=HibernateLogging">
<property name="datasourceName">java:/LoggingDS</property>
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.default_schema">dbo</property>
<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>
</session-factory>


Is the fact that I am trying to read a SQL Server 'table view' the source of my problem? I believe this to be the case because the exact same declarative transaction configuration otherwise works for my other data sources (which are not table views). Note that I can read the database just fine if I manually do session.beginTransaction() and session.getTransaction().commit(); the powers-that-be prefer the declarative approach and I have been stuck on this few a while now.


Code / Configuration:


Versions:



JDK 7u71
Maven 3.0.5
Tomcat 8.0.18
Spring 4.1.5.RELEASE
Hibernate 4.2.18.Final
CXF 3.0.4
Hibernate JPA API 2.0 1.0.1.Final
asm 3.1
cglib-nodep 2.2.2
JTDS 1.3.1


Spring autowiring is used to wire an exposed web service to a workflow to the dao.


DAO:



@org.springframework.stereotype.Repository("LogMessageViewDAO")
@EnableTransactionManagement
@Transactional(
value="LogAdminTxManager",
isolation=Isolation.READ_UNCOMMITTED,
readOnly=true)
public class LogMessageViewDAOImpl extends LogMessageViewDAO { ... }


Workflow (invoked by web service, invokes DAO):



@org.springframework.stereotype.Service("LogAdminWorkflow")
public class LogAdminWorkflow {

@Autowired LogMessageViewDAOImpl LogMessageViewDAO;

public void setLogMessageViewDAO(LogMessageViewDAOImpl logMessageViewDAO) {
LogMessageViewDAO = logMessageViewDAO;
}

...
}


CXF-Based Web Service (invokes workflow):



@WebService(
endpointInterface="x.y.z.session.LogAdministrationIF",
portName="LogAdministrationIFPort",
serviceName="LogAdministrationIFService")
public class LogAdministrationBean implements LogAdministrationIF {

@Autowired LogAdminWorkflow LogAdminWorkflow;

public void setLogAdminWorkflow(LogAdminWorkflow logAdminWorkflow) {
LogAdminWorkflow = logAdminWorkflow;
}

...
}


Spring context file:



<context:annotation-config />

<!-- DAOs -->
<context:component-scan base-package="x.y.z.dao" />

<!-- Workflows -->
<context:component-scan base-package="x.y.z.workflow" />

<!-- SOAP Web Services -->
<jaxws:endpoint id="LogAdministrationWS"
address="/logAdministration">
<jaxws:implementor>
<bean class="x.y.z.session.LogAdministrationBean"></bean>
</jaxws:implementor>
</jaxws:endpoint>

<!-- Data Sources -->
<bean id="logadminDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/comp/env/jdbc/FastAdminLoggingDS" />
<property name="lookupOnStartup" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>

<!-- Session Factory -->
<bean
id="HibernateLogAdminFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
</props>
</property>

<!-- Scan Entities -->
<property name="packagesToScan" value="x.y.z.dao.logadmin" />

<property name="dataSource">
<ref bean="logadminDataSource" />
</property>
</bean>

<!-- Transaction Manager -->
<bean id="LogAdminTxManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="logadminDataSource" />
<property name="sessionFactory" ref="HibernateLogAdminFactory" />
<qualifier value="LogAdminTxManager"/>
</bean>
<tx:annotation-driven transaction-manager="LogAdminTxManager" />


The data source is defined by my Tomcat server, so I have a ResourceLink to it in the web application's context.xml:



<ResourceLink
name="jdbc/FastAdminLoggingDS"
global="jdbc/FastAdminLoggingDS"
auth="Container" type="javax.sql.DataSource" />

Aucun commentaire:

Enregistrer un commentaire