为什么我不能在 Spring 中使这个 bean @Transactional ?

发布于 2024-11-16 09:57:12 字数 2821 浏览 1 评论 0原文

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

创建 ServletContext 资源 [/WEB-INF/spring/servlet-context.xml] 中定义的名为“vecchiOrdiniFiller”的 bean 时出错:调用 init 方法失败;嵌套异常是 org.hibernate.HibernateException:没有 Hibernate Session 绑定到线程,并且配置不允许在此处创建非事务性会话

但这是配置(与服务非常相似):

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

并且我注释了init () 方法与@Transactional。但它不会启动事务,并且我收到该错误:

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

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

为什么这不起作用?

I'm writing a simple bean that I want to configure with a table name, an XML file with some data, so that if at application startup the table is empty it get initialized with that data. I decided to use simple SQL queries, but I can't get a session from the sessionfactory, because it says:

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

But this is the configuration (very similar to a service):

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

and I annotated the init() method with @Transactional. But it doesn't start a transaction and I get that error:

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

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

why doesn't that work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

锦爱 2024-11-23 09:57:12

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

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

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

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

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

The init-method or @PostConstruct annotated methods are not proxied, so you will not be able to use @Transactional on that. You should use @Transactional on your service, why is that not suitable for you?
Quoted from the SpringSource Jira:

This is as defined, actually: init methods (such as @PostConstruct methods) are always called on the target instance itself. The proxy will only be generated once the target instance has been fully initialized... In other words, the @Transactional proxy isn't even created at the point of the @PostConstruct call yet.

Switching to mode="aspectj" would help since it weaves the target class directly, in which case the init method will have been modified for transactional awareness at the time of the container init call already.

I guess at the very minimum, we should document the limitations of @Transactional on proxies more clearly - and point out where mode="aspectj" might be a solution.

As stated, you can try the mode="aspectj" but rather you should review your design in my opinion.

故事与诗 2024-11-23 09:57:12

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

I don't think you can make the init method transactional. But you can invoke another transactional method of another service from it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文