Hibernate 和 Spring:尝试创建事务时出现异常

Posted

技术标签:

【中文标题】Hibernate 和 Spring:尝试创建事务时出现异常【英文标题】:Hibernate & Spring: Exception when trying to create a transaction 【发布时间】:2015-12-30 03:25:06 【问题描述】:

所以我第一次尝试使用 Spring 来管理休眠事务,但出了点问题。我不确定是什么。我在这个网站上查看了一堆类似的答案,但我所看到的似乎都不是正确的。

所以,我将复制并粘贴一堆我的代码以及一些解释,并在这里寻求帮助。

这是我得到的异常的堆栈跟踪。本质上,它似乎正在尝试找到 org.hibernate.engine.transaction.spi.transactioncontext,并且无法。

异常堆栈跟踪

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)

现在,我搜索了这个站点,我看到的最重要的事情是,这意味着我的 pom.xml 中有一个错误的依赖项。问题是,我的 pom.xml 中有最新版本的 hibernate-core 依赖项。根据我的阅读,这就是我这门课所需要的。

pom.xml 依赖项

<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>

另外,我正在调用的 DAO 中添加实际方法。此方法是在抛出异常时尝试运行的方法。

DAO 方法:

@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;

最后,这是我的 spring-context-data.xml。它包含我的 spring 数据 bean 的所有配置,以及事务的东西:

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>

所以我只是不知道为什么会这样。我已经两次和三次检查了我所做的与我在网上看到的内容,我看不到错误。这是我第一次尝试使用 Spring 事务管理。任何帮助将不胜感激。

PS。我正在同时使用 Spring 4 和 Hibernate 5,如果这会有所不同的话。

【问题讨论】:

您正在根据 Spring 使用 hibernate4,但您有 hibernate5 依赖项。切换到正确的LocalSessionFactoryBean 或切换到 hibernate4 都行不通 您到底拥有哪个版本的 Spring 4?只有 Spring 4.2 及更高版本支持 Hibernate 5。如果您有 Spring 4.1,则可以使用 Hibernate 4.3 作为最高版本。 如果更改休眠事务管理器和会话工厂不起作用,请尝试在 pom xml 中将 mysql 连接器从 5.1.36 更改为 5.1.46 版本:mysql mysql-connector-java5.1.36 【参考方案1】:

您正在使用 hibernate-5,但您要求 spring 使用 hibernate-4 sessionFactory

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

和事务管理器

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">

【讨论】:

【参考方案2】:

我遇到了同样的问题,我的问题通过更新得到了解决

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

【讨论】:

你没有看到这个确切的方法已经有人发布了吗?您最好发表评论而不是将此作为答案发布。【参考方案3】:

在您的 POM 中,您依赖于 Hibernate 5,但在您的事务管理器中,您使用的是 Hibernate 4。

更改您的事务管理器以匹配您的 pom(即从 hibernate4 到 hibernate5):

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

如果这导致找不到类错误,请将您的 spring 框架升级到 4.2.2

【讨论】:

谢谢!工作对我来说就像一个魅力。 看起来这是正确的答案,但你能把它翻译成@annotation模式吗,你的答案会更完美和有用......谢谢。 救了我一天 :) 拯救了我的夜晚! ;) 谢谢....对于使用注释的人,请查看您的导入:import org.springframework.orm.hibernate5.HibernateTransactionManager; @Tom Chamberlain 请在您的回答中添加注释以确保在需要时也设置 sessionFactory:【参考方案4】:

它正在寻找的类是指一个只存在于 Hibernate 4.x 中的类 http://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/engine/transaction/spi/package-summary.html

但在 5.x 中不再有 http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/engine/transaction/spi/package-summary.html

所以我认为您可能正在混合 Hibernate 4 和 5 依赖项。我不认为你可以在不查看所有依赖项的情况下切换休眠版本。

【讨论】:

那么我应该恢复到 Hibernate 4 吗?我所有的问题都会解决吗? 尤里卡!那行得通,非常感谢。所以唯一剩下的错误是现在,一些hibernate的日志记录在控制台中打印出来,而不是被路由到我在log4j2中的fileAppender。这在我使用版本 5 时没有发生。我的 POM 具有我必须确保所有 slf4j 日志记录正确路由的依赖项,知道发生了什么吗? (小细节,我知道,但我非常注重细节) “一些hibernate的日志记录”到底是什么?我宁愿为此打开一个关于 *** 的新问题,以便得到正确的关注,您可以发布一些示例配置。【参考方案5】:

不确定这是否是问题,但由于您认为与 pom.xml 有关,请尝试添加休眠的实体管理器依赖项。我比较了你的 pom.xml 和我的,关于 hibernate 的依赖,这是缺少的。

【讨论】:

你能具体说明我缺少什么依赖项吗? 就在这里mvnrepository.com/artifact/org.hibernate/…

以上是关于Hibernate 和 Spring:尝试创建事务时出现异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring-boot & hibernate,使用事务

使用 Spring @Transactional 管理 Hibernate 事务

Spring 和 Hibernate 的长时间运行事务?

Spring & Hibernate - 使本机查询在与@Transactional 相同的事务中运行

Spring管理 hibernate 事务配置的五种方式

java - 如何在Java Spring和Hibernate的单个事务中管理2个DAO方法?