java - spring mvc + jpa + hibernate + transaction issue -
i seem unable persist data in db using injected entitymgr in spring mvc. have seen multiple similar questions (like entitymanager cannot use persist save element database) , none of answers seem solve issue. here config:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <!-- datasource --> <bean id="datasource" class="org.apache.commons.dbcp.basicdatasource" destroy-method="close" p:driverclassname="${driver}" p:url="${url}" p:username="contact" p:password="contact" /> <context:property-placeholder location="classpath:jdbc.properties" /> <bean id="entitymanagerfactory" class="org.springframework.orm.jpa.localcontainerentitymanagerfactorybean" p:datasource-ref="datasource" p:packagestoscan="com.rd.web"> <!-- scans entities (model) --> <property name="persistenceprovider"> <bean class="org.hibernate.ejb.hibernatepersistence" /> </property> <property name="jpaproperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.mysql5dialect </prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <bean id="transactionmanager" class="org.springframework.orm.jpa.jpatransactionmanager" p:entitymanagerfactory-ref="entitymanagerfactory" /> <tx:annotation-driven transaction-manager="transactionmanager"/> <context:component-scan base-package="com.rd.web" /> <bean id="contactservice" class="com.rd.web.service.contactserviceimpl"/> </beans>
i have following code in (was in web controller moved service testing):
test_case1 (using spring transaction):
@transactional public contact setcontact(contact c){ if(c.getid() == null){ getemgr().persist(c); }else{ getemgr().merge(c); } return c; }
==> no error, entity isn't inserted, no insert statement in log.
test_case2 (using spring transaction):
@transactional public contact setcontact(contact c){ if(c.getid() == null){ getemgr().persist(c); }else{ getemgr().merge(c); } getemgr().flush(); return c; }
==> exception got: no transaction in progress
test_case3:
public contact setcontact(contact c){ getemgr().gettransaction().begin(); try{ if(c.getid() == null){ getemgr().persist(c); }else{ getemgr().merge(c); } getemgr().flush(); getemgr().gettransaction().commit(); return c; }catch(throwable t){ getemgr().gettransaction().setrollbackonly(); } return null; }
==> throws error: java.lang.illegalstateexception: not allowed create transaction on shared entitymanager - use spring transactions or ejb cmt instead
it should not spring aop issue since operation public , called component (in service injected). appcontext defines transactions annotion driver . don't why transactions not started.
when use same applicationcontext.xml , trigger testclass loads contactservice , creates contact, contact saved correctly.
also have added following filter in web.xml, no avail:
<filter> <filter-name>springopenentitymanagerinviewfilter</filter-name> <filter-class>org.springframework.orm.jpa.support.openentitymanagerinviewfilter</filter-class> </filter> <filter-mapping> <filter-name>springopenentitymanagerinviewfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
any hints appreciated. cheers.
added information:
@muel, entitymgr being injected using persistencecontext:
@transactional
@service("contactservice") public class contactserviceimpl implements icontactservice {
// @autowired // private ientitymgrprovider emgrpovider;
@persistencecontext entitymanager emgr; @transactional public contact getcontactbyid(long id) { return getemgr().find(contact.class, id); } @transactional public list<contact> getallcontacts() { typedquery<contact> qry = getemgr().createnamedquery("findall", contact.class); return qry.getresultlist(); } @transactional public contact setcontact(contact c){ if(c.getid() == null){ getemgr().persist(c); // getemgr().flush(); }else{ getemgr().merge(c); } return c; } @transactional(readonly=true) public void deletecontact(long id){ getemgr().remove(getemgr().find(contact.class, id)); } private entitymanager getemgr(){ // return emgrpovider.getemgr(); return emgr; } public static void main(string[] args) { classpathxmlapplicationcontext ctx = new classpathxmlapplicationcontext("appctx.xml"); icontactservice contactservice = ctx.getbean("contactservice", icontactservice.class); contact c= new contact(); c.setbirthdate(new date()); c.setfirstname("p1"); c.setlastname("p2"); contactteldetail tel = new contactteldetail(); tel.setcontact(c); tel.settelnumber("056776650"); tel.setteltype("landline"); c = contactservice.setcontact(c); system.out.println(c.getid()); } }
i realize getemgr() method not necessary emgr came somewhere else (where injected, nevermind now) btw, when run main method, can insert contact...
@user2264997 servlet context:
<?xml version="1.0" encoding="utf-8"?>
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- definition of root spring container shared servlets , filters --> <context-param> <param-name>contextconfiglocation</param-name> <param-value>/web-inf/spring/root-context.xml</param-value> </context-param> <!-- creates spring container shared servlets , filters --> <listener> <listener-class>org.springframework.web.context.contextloaderlistener</listener-class> </listener> <!-- processes application requests --> <servlet> <servlet-name>appservlet</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class> <init-param> <param-name>contextconfiglocation</param-name> <param-value>/web-inf/spring/appservlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appservlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>encodingfilter</filter-name> <filter-class>org.springframework.web.filter.characterencodingfilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceencoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>springopenentitymanagerinviewfilter</filter-name> <filter-class>org.springframework.orm.jpa.support.openentitymanagerinviewfilter</filter-class> </filter> <filter-mapping> <filter-name>springopenentitymanagerinviewfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
i have added last 2 filters testing. don't think should required (it seems last filter supporting lazy loading or something, tried anyway ...)
@martin frey
i'll have on something.
@mdeinum.wordpress.com
the service injected in webcontroller using @autowired. service implementation , web.xml see above. config file dispatcher servlet (allthough not seem have relevant information, maybe problem ;) ):
<?xml version="1.0" encoding="utf-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemalocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- dispatcherservlet context: defines servlet's request-processing infrastructure --> <!-- use dispatcher servlet root --> <!-- <default-servlet-handler/> --> <resources location="/, classpath:/meta-inf/web-resources/" mapping="/resources/**"/> <interceptors> <beans:bean class="org.springframework.web.servlet.theme.themechangeinterceptor"/> <beans:bean class="org.springframework.web.servlet.i18n.localechangeinterceptor" p:paramname="lang"/> </interceptors> <beans:bean class="org.springframework.ui.context.support.resourcebundlethemesource" id="themesource" /> <beans:bean class="org.springframework.web.servlet.theme.cookiethemeresolver" id="themeresolver" p:cookiename="theme" p:defaultthemename="standard" /> <beans:bean class="org.springframework.context.support.reloadableresourcebundlemessagesource" id="messagesource" p:basenames="web-inf/i18n/messages,web-inf/i18n/application" p:fallbacktosystemlocale="false" /> <beans:bean class="org.springframework.web.servlet.i18n.cookielocaleresolver" id="localeresolver" p:cookiename="locale"/> <!-- enables spring mvc @controller programming model --> <annotation-driven /> <!-- handles http requests /resources/** efficiently serving static resources in ${webapproot}/resources directory --> <!-- <resources location="/resources/" mapping="/resources/**" /> --> <!-- resolves views selected rendering @controllers .jsp resources in /web-inf/views directory --> <!-- using tiles in stead ==> different view resolver --> <!-- <beans:bean class="org.springframework.web.servlet.view.internalresourceviewresolver"> --> <!-- <beans:property name="prefix" value="/web-inf/views/" /> --> <!-- <beans:property name="suffix" value=".jsp" /> --> <!-- </beans:bean> --> <context:component-scan base-package="com.rd.web" /> <!-- add following beans --> <!-- tiles configuration --> <beans:bean class="org.springframework.web.servlet.view.urlbasedviewresolver" id="tilesviewresolver"> <beans:property name="viewclass" value="org.springframework.web.servlet.view.tiles2.tilesview" /> </beans:bean> <beans:bean class="org.springframework.web.servlet.view.tiles2.tilesconfigurer" id="tilesconfigurer"> <beans:property name="definitions"> <beans:list> <beans:value>/web-inf/layouts/layouts.xml</beans:value> <!-- scan views directory tiles configurations --> <beans:value>/web-inf/views/**/views.xml</beans:value> </beans:list> </beans:property> </beans:bean> </beans:beans>
i'll try configure hibernate adapter , let know how goes...
cheers
you duplicating component scanning in both applicationcontext.xml , servlet-context.xml.
<context:component-scan base-package="com.rd.web" />
when this, controller injected services picked component scan in servlet-context.xml not have transactions.
either explicitly specify controller packages base-package in servlet-context.xml, , non-controller packages base-package in applicatiocontext.xml.
or use exclude/include filter in component-scan declaration.
applicationcontext.xml
<context:component-scan ..> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.controller" /> ...
in servlet-context.xml
<context:component-scan ..> <context:include-filter type="annotation" expression="org.springframework.stereotype.controller" /> ...
Comments
Post a Comment