gotch4
gotch4

Reputation: 13299

Why can't I make this bean @Transactional in Spring?

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?

Upvotes: 6

Views: 2983

Answers (2)

abalogh
abalogh

Reputation: 8281

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.

Upvotes: 16

Bozho
Bozho

Reputation: 597402

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

Upvotes: 2

Related Questions