【问题标题】:Why can't I make this bean @Transactional in Spring?为什么我不能在 Spring 中制作这个 bean @Transactional?
【发布时间】:2011-06-20 14:04:05
【问题描述】:

我正在编写一个简单的 bean,我想用一个表名、一个包含一些数据的 XML 文件来配置它,这样如果在应用程序启动时表是空的,它就会使用该数据进行初始化。我决定使用简单的 SQL 查询,但我无法从 sessionfactory 获取会话,因为它说:

Error creating bean with name 'vecchiOrdiniFiller' defined in ServletContext resource [/WEB-INF/spring/servlet-context.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

但这是配置(非常类似于服务):

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

<tx:annotation-driven />

<bean id="ordiniVecchioSistemaLoader" class="it.jsoftware.jacciseweb.assistenza.common.ExcelXmlDataLoader">
    <property name="xmlFileName" value="WEB-INF/data/daticlientijaccisemarco.xml"></property>
</bean>

<bean id="vecchiOrdiniFiller" class="it.jsoftware.jacciseweb.assistenza.common.BaseTableFiller" init-method="init">
    <property name = "sessionFactory" ref = "mySessionFactory"></property>
    <property name="loader" ref="ordiniVecchioSistemaLoader"></property>    
    <property name="tableCreationString" value="CREATE TABLE `vecchiordini` (  `ID` INT(11) NOT NULL AUTO_INCREMENT,  `codicejazz` VARCHAR(255) DEFAULT NULL,  `progressivolicenza` INT(11),  `codicearticolo` VARCHAR(255) DEFAULT NULL,  `rivenditore` VARCHAR(255) DEFAULT NULL,  `cliente` VARCHAR(255) DEFAULT NULL,  PRIMARY KEY (`ID`)) ENGINE=INNODB DEFAULT CHARSET=utf8"></property>
    <property name="table" value="vecchiordini"></property>
    <property name="tableColumns">
        <list>
            <value>codicejazz</value>
            <value>progressivolicenza</value>
            <value>codicearticolo</value>
            <value>rivenditore</value>
            <value>nomecliente</value>
        </list>
    </property>
    <property name="loaderColumns">
        <list>
            <value>clicod</value>
            <value>licsmatricola</value>
            <value>artcod</value>
            <value>rivenditore</value>
            <value>cliente</value>
        </list>
    </property>
</bean>

我用@Transactional 注释了init() 方法。但它并没有开始交易,我得到了那个错误:

@Transactional
public void init() throws Exception {
    logger.info("BaseTableFilter per tabella: " + table + ", usando: "
    + loader.getSourceName());

    Session session = dao.getSession();
    Transaction tx = session.beginTransaction();
    ...

为什么不行?

【问题讨论】:

    标签: sql spring transactions


    【解决方案1】:

    init-method@PostConstruct 注释的方法没有被代理,因此您将无法在其上使用 @Transactional。您应该在您的服务上使用@Transactional,为什么它不适合您? 引用自SpringSource Jira

    这实际上是定义的:init 方法(例如@PostConstruct 方法)总是在目标实例本身上调用。只有在目标实例完全初始化后才会生成代理...换句话说,@Transactional 代理甚至在 @PostConstruct 调用时还没有创建。

    切换到 mode="aspectj" 会有所帮助,因为它直接编织目标类,在这种情况下,init 方法将在容器 init 调用时已针对事务感知进行了修改。

    我想至少,我们应该更清楚地记录@Transactional 在代理上的限制 - 并指出 mode="aspectj" 可能是一个解决方案。

    如上所述,您可以尝试mode="aspectj",但我认为您应该审查您的设计。

    【讨论】:

    • 我确实审查了我的设计......非常简单,我引用了我的服务,仅此而已。为什么我想避免这种情况?因为我想制作一个真正独立的库,甚至可以从我的服务中重用它,甚至可以在 GPL 下将它放到网上......无论如何,@Donal,当然从一开始就更容易做到这一点,但如果你从来没有推动一个新的解决方案,尽管它可能很棘手,但你永远不会得到任何新的和有用的东西。
    • 今天为此浪费了 5 个小时。如果我可以对问题进行投票并回答 1000 次,我会的!
    【解决方案2】:

    我认为您不能使 init 方法具有事务性。但是您可以从中调用另一个服务的另一个事务方法。

    【讨论】:

    • 我可以直接调用 Dao 并让 dao 方法事务化(这听起来可能很愚蠢,但到目前为止我只使服务方法事务性,所以请耐心等待)?
    • 可以,但通常不应该。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 2021-06-03
    相关资源
    最近更新 更多