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.Hibernate开发者_运维技巧TransactionManager">
<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?
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.
I don't think you can make the init method transactional. But you can invoke another transactional method of another service from it.
精彩评论