当前位置: 首页 > 知识库问答 >
问题:

Hibernate4,Spring4,Axis2和@Transactional注释未打开事务:如果没有活动事务,get无效

欧阳骏俊
2023-03-14

我想将我的axis2项目与spring集成在一起。我按照本指南加载了一个spring applicationContext。

https://axis.apache.org/axis2/java/core/docs/spring.html

简而言之
以下是我的axis2版本服务:

public class VersionService extends MyappService{

    private static final Logger log = Logger.getLogger(VersionService.class);

    @Autowired
    NewUserMyappDAO newUserMyappDAO;

    public Response getResponse(){
        Response response = new Response();
        UserMyapp ub = getTransaction();
        return response;
    }

    @Transactional
    public UserMyapp getTransaction(){
        return newUserMyappDAO.findById(13);
    }
}

问题:当轴调用 getResponse() 方法时,dao 设法获取注入的会话工厂(和Hibernate会话),但是当在方法之上使用@Transactional时,之前没有打开任何事务。这就是为什么我得到:

 Caused by: org.hibernate.HibernateException: get is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:348)
at $Proxy45.get(Unknown Source)
at com.myapp.framework.model.dao.NewMyappDAO.findById(NewMyappDAO.java:35)
at com.myapp.ws.version.VersionService.getTransaction(VersionService.java:127)
at com.myapp.ws.version.VersionService.getResponse(VersionService.java:119)

我想要的是有一个getTransaction()方法,它会自动启动事务(Hibernatesession.beginTransaction()),并在其中出现故障时回滚。

我也试着移除

<prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</prop>

但是在这种情况下,spring无法加载userMyAppDAO,因为org . hibernate . hibernate exception:没有为当前线程找到会话

详细来说,我的applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">


    <context:annotation-config />

    <context:component-scan base-package="com.myapp.framework.model.dao"></context:component-scan>

    <!-- Axis2 Web Service, but to Spring, its just another bean that has dependencies -->
    <bean id="versionService" class="com.myapp.ws.version.VersionService"/>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://db.myapp.com:3307/MyappAPI" />
        <property name="username" value="myapp" />
        <property name="password" value="myappculomyapp" />
    </bean>


    <bean id="sessionFactory"
                class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />

        <property name="packagesToScan">
            <list>
                <value>com.myapp.framework.model.dao</value>
            </list>
        </property>

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

                <prop key="hibernate.connection.CharSet">utf8</prop>
                <prop key="hibernate.connection.characterEncoding">utf8</prop>
                <prop key="hibernate.connection.useUnicode">true</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
                <prop key="hibernate.globally_quoted_identifiers">true</prop>
                <prop key="hibernate.connection.autocommit">false</prop>

                <prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</prop>
                <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory</prop>

                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>

            </props>
        </property>
    </bean>

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

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

</beans>

这是DAO及其超类:

@Repository
public class NewUserMyappDAO extends NewMyappDAO<UserMyapp, Integer>{

    @Autowired
    public NewUserMyappDAO(SessionFactory sessionFactory){
        super(UserMyapp.class, sessionFactory);
    }
}

@Repository
public abstract class NewMyAppDAO<E, ID extends Serializable>
        implements IMyAppDAO<E, ID> {

    private final Class<E> entityClass;
    protected Session session;

    public NewMyAppDAO(Class<E> entityClass, SessionFactory sessionFactory) {

        this.entityClass = entityClass;
        this.session = sessionFactory.getCurrentSession();
    }

    public Class<E> getEntityClass() {
        return entityClass;
    }

    @SuppressWarnings({ "unchecked" })
    public E findById(ID id) {
        Object obj = null;
        try {
            obj = session.get(getEntityClass(), id);
        } catch(ObjectNotFoundException e){
            return null;
        }
        return (E) obj;
    }

编辑

vp8106留下的答案似乎是正确的,但我试图后退一步,尝试以编程方式管理事务。我所做的是在getResponse()方法中显式使用beginTransaction()、commitTransaction。即使sessionFactory对象是单例对象,并且用初始化

<prop key="hibernate.current_session_context_class">thread</prop>

没有启动任何事务,我的dao仍然返回相同的异常。

共有2个答案

宗政卓
2023-03-14
匿名用户

多亏了vp816和M.Deinum,我才明白发生了什么。

>

  • 这里最大的错误是我每次调用NewMyAppDAO的findById方法时都使用相同的私有会话字段对象。使用受保护的get会话()方法允许正确使用会话。

    @Repository公共抽象类NewMyAppDAO实现IMyAppDAO{

    private final Class<E> entityClass;
    protected SessionFactory sessionFactory;
    
    public NewMyAppDAO(Class<E> entityClass, SessionFactory sessionFactory) {
    
        this.entityClass = entityClass;
        this.sessionFactory = sessionFactory;
    }
    
    protected Session getSession(){
        return  this.sessionFactory.getCurrentSession();
    }
    

    }

    使用程序化事务管理,我们必须设置属性

    <prop key="hibernate.current_session_context_class">thread</prop>
    

    Spring设置:

    <tx:annotation-driven>
    

    在这种情况下毫无用处。

    如果我们想要使用spring注释驱动的事务,我们必须:< br> a)从sessionFactory bean配置中删除< code > hibernate . current _ session _ context _ class 属性< br> b)添加Spring设置< code >

    @Service公共类版本处理程序 {

    @Autowired
    NewUserMyappDAO newUserMyappDAO;
    
    @Transactional
    public UserMyapp getUserMyapp(int transactionId){
        return newUserMyappDAO.findById(transactionId);
    }
    

    }

  • 祁晟
    2023-03-14

    很可能是Axis调用了spring bean的< code>getResponse方法,而该方法没有标记< code>@Transactional。事实上,spring为beans创建了一个动态代理,它的方法用< code>@Transactional进行了注释。此代理包装对事务处理方法的调用,在目标方法执行之前启动事务,在目标方法执行之后提交。但是在您的情况下,方法< code>getResponse调用此bean的方法< code>getTransaction,而不是代理。因此,事务感知代码不会执行,也不会启动任何事务。< br>
    最简单的解决方案是用< code>@Transactional而不是< code>getTransaction来标记< code>getResponse方法。注意:只有在spring生成的代理上调用< code>getResponse时,它才会起作用,这在您提供的stacktrace中并不清楚。

    编辑
    在Spring环境中,您应该使用

    <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
    

    它将hibernate会话生命周期绑定到Spring的HibernateTransactionManager为了启动、提交或回滚事务,应使用HibernateTransactionManager的.getTransaction(…)提交(…)回滚(…)。要以编程方式管理事务,最好使用TransactionTemplate,它可以帮助您避免编写样板代码来开始、提交或回滚事务。

     类似资料:
    • 问题内容: 我正在尝试使用Spring @Transactional批注,但是在调用方法 findAll 时遇到问题,并且出现以下错误: 人DAO: 这是我的: 我尝试删除此行,但是又出现了一个错误,为什么这行不通? 问题答案: 您必须明确声明对事务管理器注释的支持 添加到您的配置中: tx是xmlns:tx =“ http://www.springframework.org/schema/tx”

    • 在我的应用程序中,我有2个transactionManager,创建如下: 在同一个文件中,我有注释驱动的声明: 为了简化admin transactionManager的可用性,我创建了一个简单的注释: 这是我的带有事务注释的方法: 由于有接口,该方法是从另一个类调用的。bean由Spring@Autowired注释注入。jdbcTemplate对象是用以下代码创建的: 我的问题是当我执行jdb

    • 问题内容: 我正在使用Spring注释来管理我的事务,如下所示: 我想知道如果忘记注释会发生什么: 当alertDAO实现如下时: 似乎Hibernate允许我从数据库中获取数据,即使没有注释也是如此。 这种粗心大意的后果是什么?可能发生的最坏情况是什么? 问题答案: 根据文档(Spring docs ),它仅仅是元数据,它表明方法或接口可以由“具有交易意识的”事物(例如)进行配置。 相信只有 t

    • 我在我的应用程序中使用了Spring冬眠球衣。我想使用事务,因此我在服务图层中使用了 spring @Transactional 注记。这是我的Hibernate.cfg.xml: 我没有在这里使用session_context,所以Spring可以管理它。在我的应用程序Context.xml中,我定义了事务管理器: 所有与 /api/v1/* 匹配的 url 都映射到名为泽西岛的服务器和使用的

    • 问题内容: 之间有什么区别? 在整个类中添加“ @Transactional”注释 为每个方法添加“ @Transactional”注释? 使用spring和Hibernate吗? 问题答案: 基本上,如果您用所有方法注释该类,则将是事务性的。如果您不这样做,则可以仅将其标注为所需的方法。此外,你可以为每个方法指定不同的属性,如,,,…

    • 问题内容: 我正在创建应用程序并在其中使用一些hibernate的东西。我要做的就是将实体保存到数据库中,但我不断收到此异常: 起初,我遇到了这个异常: 然后,我发现需要将其添加到我的hibernate配置中: 这解决了这个问题,但是现在出现了上面的问题。我将实体保存到这样的数据库中: 我的hibernate.cfg.xml文件如下所示: 我在用: Hibernate-4.1.4.Final JD