【问题标题】:Hibernate transaction begin and commit at the right point休眠事务开始并在正确的点提交
【发布时间】:2016-08-15 11:56:05
【问题描述】:

我有一个 dao 包,其中我的所有 DaoClasses 都实现了以下方法:

public class XDaoImpl implements XDao {

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    @Override
    public void saveOrUpdate(MyObject o) {
            //Transaction trans = getSessionFactory().getCurrentSession().beginTransaction();
            getSessionFactory().getCurrentSession().saveOrUpdate(o); 
            //trans.commit();
        }
}

如果我运行我的应用程序,则需要很长时间才能将我的对象存储到数据库中。我相信它会发生,因为我为每个对象创建了一个新的事务。所以我尝试使用 Spring Framework 的基于 xml 的声明式事务实现。但直到现在它对我不起作用:

<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"
     xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>/resources/spring/config/database.properties</value>
        </property>
    </bean>


    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>


    <bean id="hibernate3SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

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

        <property name="mappingResources">
            <list>
                <value>/resources/spring/config/A.hbm.xml</value>
                <value>/resources/spring/config/B.hbm.xml</value>
                <value>/resources/spring/config/C.hbm.xml</value>
                <value>/resources/spring/config/D.hbm.xml</value>
            </list>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>

    </bean>

    <bean id="dBo" class="com.model.bo.DBoImpl">
        <property name="dDao" ref="dDao" />
        <property name="bDao" ref="bDao" />
    </bean>

    <bean id="dDao" class="com.model.dao.dDaoImpl">
        <property name="sessionFactory" ref="hibernate3SessionFactory" />
    </bean>

    <bean id="aBo" class="com.model.bo.aBoImpl">
        <property name="aDao" ref="aDao" />
        <property name="bDao" ref="bDao" />
        <property name="cDao" ref="cDao" />
    </bean>

    <bean id="bDao" class="com.model.dao.bDaoImpl">
        <property name="sessionFactory" ref="hibernate3SessionFactory" />
    </bean>

    <bean id="cDao" class="com.model.dao.cDaoImpl">
        <property name="sessionFactory" ref="hibernate3SessionFactory" />
    </bean>
    <bean id="aDao" class="com.model.dao.aDaoImpl">
        <property name="sessionFactory" ref="hibernate3SessionFactory" />
    </bean>

     <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="hibernate3SessionFactory" />
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="boMethods" expression="execution(* com.model.bo.*.*(..))" />

        <aop:advisor advice-ref="txAdvice" pointcut-ref="boMethods" />
    </aop:config> 
    </beans>

抛出的错误:

类 org.springframework.beans.factory.BeanCreationException 错误 创建在类路径资源中定义的名称为“dataSource”的bean [resources/spring/config/BeanLocations.xml]: BeanPostProcessor 之前 bean 的实例化失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:错误 用名字创建bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': 设置 bean 时无法解析对 bean 'boMethods' 的引用 属性“切入点”;嵌套异常是 org.springframework.beans.factory.BeanCreationException:错误 创建名为“boMethods”的 bean:bean 实例化失败; 嵌套异常是 java.lang.NoClassDefFoundError: org/aspectj/weaver/BCException

public class DBoImpl implements DBo {

    private DDao dDao;
    private BDao bDao;


    public DDao getDDao() {
        return dDao;
    }

    public void setDDao(DDao dDao) {
        this.dDao = dDao;
    }

    public BDao getbDao() {
        return bDao;
    }

    public void setbDao(BDao bDao) {
        this.bDao = bDao;
    }

public D add(D r) {
        dDao.saveOrUpdate(r);
        return r;
    }

}

【问题讨论】:

    标签: java spring hibernate


    【解决方案1】:

    您的类路径中似乎没有 AOP jar 文件。

    见: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html

    查找“10.2.1 启用@AspectJ 支持”部分

    【讨论】:

    • 谢谢,与我的 Dao-Beans 包含 sessionFactory 相比,我是否还为 Transaction 对象提供了 Getter 和 Setter 方法并将其添加到我的 aBo- 和 dBo-Bean 中?
    • 我还用Transaction trans = getSessionFactory().getCurrentSession().beginTransaction(); trans.commit();这行了吗?我问是因为我删除了这些行并收到错误:class org.hibernate.HibernateException saveOrUpdate is not valid without active transaction
    • 我相信这是正确的。您应该只需要调用 getCurrentSession().saveOrUpdate()。这可能是 aop 配置的问题,尽管到目前为止它对我来说看起来不错......仍在查看它。
    • aop 表达式是否正确?是com.model.bo 还是com.model.dao 中需要事务支持的daos。我看到在 com.model.dao 中定义了一些 daos。您可能想尝试将表达式更改为 execution(* com.model.dao.*.*(..))
    • 请查看我的编辑,我为我的 dao 类和 bo 类添加示例。
    【解决方案2】:

    将 AOP 用于事务行为很好。我建议看看annotation based configuration(注意&lt;tx:annotation-driven transaction-manager="transactionManager" /&gt;),这可能更简单一些。

    此外,我会小心使用此配置。事务旨在封装一个原子工作单元。拥有像saveOrUpdate(EntityType entity) 这样的方法我认为您的原子工作单元正在保存一个实体,而不是保存n 个实体。事务运行的时间越长,发生死锁的可能性就越大。

    我建议创建一个像 public void saveOrUpdateInBatch(MyObject... objects) 这样的方法。顾名思义,您正在处理一个处理许多元素的原子操作。此外,您可能希望针对批量插入优化此方法。

    【讨论】:

    • 您是否在第二段中提到,如果我使用 aop 配置而不是在方法 saveOrUpdate 中创建 Transaction 对象,性能不会有任何改变?
    • 不,您的新配置将提高性能,因为 Spring 将创建一个事务,该事务也将用于后续调用。应该完全避免自己创建事务,这是 spring 可以为您以干净美观的方式处理的工作。不过,在我看来,为批量更新创建一个独特的方法将是一种更简洁的方法。
    • 现在我想起来了,如果你从 spring 上下文之外调用你的 saveOrUpdate 方法,我不确定 spring 是否会重用事务。如果我没记错的话,您的调用方法必须声明为事务方法才能获得性能影响。话虽如此,如果您有一种专门的方法来进行批量更新,一切都会变得更干净。
    • 我尝试使用注释我将我的 LocationBean 更改为 &lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt; &lt;property name="sessionFactory" ref="hibernate3SessionFactory" /&gt; &lt;/bean&gt; &lt;tx:annotation-driven transaction-manager="transactionManager" /&gt; 并将 @Transactional(propagation=Propagation.REQUIRED) 行放在包 bo 和 dao 中的所有类定义之前。它出现了同样的错误:class org.hibernate.HibernateException saveOrUpdate is not valid without active transaction
    • 请从您的 applicationcontext.xml 中删除 线程。根据forum.spring.io/forum/spring-projects/data/…,这似乎是问题所在
    猜你喜欢
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    • 2011-04-05
    • 2013-05-04
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2015-02-09
    相关资源
    最近更新 更多