Hibernate & Spring: Exception when trying to create a transaction
Asked Answered
L

5

16

So I'm trying to use Spring to manage hibernate transactions for the first time, and something's going wrong. I'm not sure what. I've looked at a bunch of similar answers on this site and nothing I've seen seems to be right.

So, I'm gonna copy and paste a bunch of my code with some explanations and ask for help here.

Here is a stack trace of the exception I'm getting. Essentially, It seems that it's trying to find org.hibernate.engine.transaction.spi.transactioncontext, and can't.

Exception stack trace

EXCEPTION: Could not open Hibernate Session for transaction; nested exception is java.lang.NoClassDefFoundError: org/hibernate/engine/transaction/spi/TransactionContext
org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:544)
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:427)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy42.getSavedPortfolios(Unknown Source)
io.craigmiller160.stockmarket.controller.StockMarketController.showOpenPortfolioDialog(StockMarketController.java:994)
io.craigmiller160.stockmarket.controller.StockMarketController.parseEvent(StockMarketController.java:431)
io.craigmiller160.stockmarket.controller.StockMarketController.processEvent(StockMarketController.java:336)
io.craigmiller160.mvp.concurrent.AbstractConcurrentListenerController$1.run(AbstractConcurrentListenerController.java:209)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)

Now, I've searched this site, and the big thing I saw was that this means I have a dependency wrong in my pom.xml. The thing is, I have the most up-to-date version of the hibernate-core dependency in my pom. From what I've read, that's what I need for this class.

pom.xml dependencies

<dependencies>
<!-- JUnit Testing -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
<!-- MVP Framework -->
    <dependency>
        <groupId>io.craigmiller160.mvp</groupId>
        <artifactId>mvp-framework</artifactId>
        <version>2.1.1</version>
    </dependency>
<!-- MigLayout -->
    <dependency>
        <groupId>com.miglayout</groupId>
        <artifactId>miglayout-swing</artifactId>
        <version>5.0</version>
    </dependency>
<!-- JFreeChart -->
    <dependency>
        <groupId>org.jfree</groupId>
        <artifactId>jfreechart</artifactId>
        <version>1.0.19</version>
    </dependency>
<!-- Java Concurrency In Practice Annotations -->
    <dependency>
        <groupId>net.jcip</groupId>
        <artifactId>jcip-annotations</artifactId>
        <version>1.0</version>
    </dependency>
<!-- Joda Time -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.8.2</version>
    </dependency>
<!-- MySQL ConnectorJ -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.36</version>
    </dependency>
<!-- Spring Framework Core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
<!-- Spring Framework Beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
<!-- Spring Framework Context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
<!-- Hibernate Core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.0.1.Final</version>
    </dependency>
<!-- XML Framework -->
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
    </dependency>
<!-- Code Generation library -->
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.1</version>
    </dependency>
<!-- Apache Commons Logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
<!-- LOG4J API -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>${log4j.version}</version>
    </dependency>
<!-- LOG4J Core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>${log4j.version}</version>
    </dependency>
<!-- SLF4J/LOG4J Binding -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>${log4j.version}</version>
    </dependency>
<!-- LOG4J/Commons Logging Binding -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-jcl</artifactId>
        <version>${log4j.version}</version>
    </dependency>
<!-- SLF4J API -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.12</version>
    </dependency>
<!-- Spring ORM -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>
<!-- AspectJ Runtime -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
<!-- AspectJ Weaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
<!-- Apache Database Connection Pooling -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp2</artifactId>
        <version>2.1.1</version>
    </dependency>
</dependencies>

Also, I'm adding the actual method in my DAO that I'm calling. This method is what is attempting to run when the exception is thrown.

DAO method:

@Transactional
@Override
@SuppressWarnings("unchecked") //hibernate list() method doesn't support generics
public List<String> getSavedPortfolios() throws HibernateException {
    List<String> portfolioNames = new ArrayList<>();

    List<SQLPortfolioModel> portfolioList = sessionFactory.getCurrentSession()
                                .createCriteria(PortfolioModel.class)
                                .list();

    for(SQLPortfolioModel portfolio : portfolioList){
        int id = portfolio.getUserID();
        String name = portfolio.getPortfolioName();
        BigDecimal netWorth = portfolio.getNetWorth();
        Calendar timestamp = portfolio.getTimestamp();

        String fileName = String.format("%1$d-%2$s-%3$s-"
                +"%4$s", id, name, moneyFormat.format(netWorth), 
                timestampFormat.format(timestamp.getTime()));
        portfolioNames.add(fileName);
    }

    return portfolioNames;
}

Lastly, here is my spring-context-data.xml. It contains all the configuration for my data beans for spring, plus the transaction stuff:

spring-context-data.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- Sets annotation-driven transactions -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- DataSource object for providing database connections -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/stockmarket"/>
    <property name="username" value="stockmarket"/>
    <property name="password" value="stockmarket"/>
</bean>

<!-- SessionFactory object for creating sessions for database access -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- <property name="configLocation" value="classpath:hibernate.cfg.xml"/>-->
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="connection.pool_size">1</prop>
            <prop key="show_sql">false</prop>
            <!-- Might need this one below for transactions, not sure yet -->
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
        </props>
    </property>
    <property name="annotatedClasses">
        <list>
            <value>io.craigmiller160.stockmarket.stock.AbstractStock</value>
            <value>io.craigmiller160.stockmarket.stock.OwnedStock</value>
            <value>io.craigmiller160.stockmarket.stock.DefaultStock</value>
            <value>io.craigmiller160.stockmarket.stock.DefaultOwnedStock</value>
            <value>io.craigmiller160.stockmarket.model.PortfolioModel</value>
            <value>io.craigmiller160.stockmarket.model.SQLPortfolioModel</value>
        </list>
    </property>
</bean>

<!-- Hibernate Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!-- HibernateDAO class for performing database operations -->
<bean id="hibernateDao" class="io.craigmiller160.stockmarket.controller.HibernatePortfolioDAO"
    destroy-method="closeFactory">
    <constructor-arg ref="sessionFactory"/>
</bean>

 </beans>

So I just have no idea why this is happening. I've double and triple checked what I did versus what I'm seeing online, and I can't see the mistake. This is my first time trying to use Spring transaction management. Any help would be greatly appreciated.

PS. I'm using Spring 4 & Hibernate 5 together, if that makes a difference.

Lavery answered 1/10, 2015 at 23:26 Comment(3)
You are using hibernate4 according to Spring but you have hibernate5 dependencies. That isn't going to work either switch to the correct LocalSessionFactoryBean or switch to hibernate4Ela
Which version of Spring 4 do you have exactly? Only Spring 4.2 and upwards support Hibernate 5. If you have Spring 4.1, then you can use Hibernate 4.3 as highest version.Slit
If changing the hibernate transaction manager and session factory doesn't work, try changing your mysql connector to version 5.1.46 from 5.1.36 here in your pom xml : <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.36</version> </dependency>Soapberry
P
45

In your POM you are depending on Hibernate 5, but in your transaction manager, you are using Hibernate 4.

Change your transacation manager to match your pom (i.e. from hibernate4 to hibernate5):

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

If that causes a class not found error, upgrade your spring framework to 4.2.2

Portal answered 29/10, 2015 at 11:25 Comment(5)
It look like this is the right answer but can you translate* it to @annotation mode, Your answer well be more perfect and usefull... and thanks.Operative
Saved me a day :)Tricrotic
Saved my night! ;) thanks....To people using annotations, take a look at your imports: import org.springframework.orm.hibernate5.HibernateTransactionManager;Ratter
@Tom Chamberlain Please add to your answer a note to make sure to set also the sessionFactory if required: <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">Consummation
I am already using "org.springframework.orm.hibernate5.HibernateTransactionManager" and "org.springframework.orm.hibernate5.LocalSessionFactoryBean" but still getting this exception. Can someone help please ?Soapberry
A
5

The class it is looking for is referring to a class that only exists in Hibernate 4.x http://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/engine/transaction/spi/package-summary.html

But no more in 5.x http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/engine/transaction/spi/package-summary.html

So I think you might be mixing Hibernate 4 and 5 dependencies. I don't think you can just switch the hibernate version without reviewing all of its dependencies.

Anklebone answered 1/10, 2015 at 23:47 Comment(3)
So should I just revert to Hibernate 4 then? And all my problems will be solved?Lavery
Eureka! That worked, thanks so much. So only remaining bug is that now, some of hibernate's logging is printing out in the console rather than being routed to my fileAppender in log4j2. This wasn't happening when I was using version 5. My POM has the dependencies I have to make sure that all the slf4j logging gets routed properly, any idea what's going on? (Minor detail, I know, but I'm very detail oriented)Lavery
"some of hibernate's logging " is what exactly? I would rather probably open a new question on stackoverflow for this, so that it gets the right attention and you can post some example configs.Anklebone
O
2

You are using hibernate-5 but you are asking spring to use hibernate-4 sessionFactory

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

and transaction manager

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
Offing answered 31/5, 2016 at 0:16 Comment(0)
S
0

Not sure if this is the problem, but since you think is something related to the pom.xml try adding the hibernate's entity manager dependency. I compared your pom.xml with mine and, with regards to the hibernate's dependencies, this is the one lacking.

Sheave answered 1/10, 2015 at 23:42 Comment(2)
can you specify exactly what dependency I'm missing?Lavery
right here mvnrepository.com/artifact/org.hibernate/…Sheave
F
-3

I was getting the same problem and my problem get solved by updating

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

Flattery answered 29/1, 2016 at 23:38 Comment(1)
Didn't you see that this exact approach was issued by someone already? It's better you comment than post this as an answer.Headstream

© 2022 - 2024 — McMap. All rights reserved.