in spring mvc application, have method in controller needs save bunch of objects (built uploaded file) database. let leave aside moment whole question whether transactions should done in controller or service layer -- point should technically feasible in controller, finding problems. if @ code below, expecting if of 3 calls savecontact fails exception (any exception, since put rollbackfor = exception.class ), 3 should rolled back. still, see if example third 1 fails, data first 2 still present in database. exception thrown persistenceexception, believe should trigger rollback, doesn't (it bubbles client's browser, expected since i'm not catching it).
here's controller code:
package ch.oligofunds.oligoworld.web; /*imports here*/ /** * handles requests application file upload requests */ @controller("exceluploaderimpl") @transactional public class exceluploaderimpl implements exceluploader { @autowired personinfodao personinfodao; /** * upload files using spring controller * @throws securityexception * @throws nosuchmethodexception * @throws dataaccessexception */ @override @requestmapping(value = "/importfundnav", method = requestmethod.post) public @responsebody string handlefileupload(httpservletrequest request, @requestparam commonsmultipartfile[] fileupload) throws dataaccessexception, nosuchmethodexception, securityexception { /*here save uploaded file , initialize serverfile variable*/ try { success = readexcelfile(serverfile); } catch (ioexception e) { logger.error("failed read excel file", e); result += "failed read excel file\n" + e.getstacktrace() + "\n"; } { serverfile.delete(); } if (success) { result += "you imported file " + afile.getoriginalfilename() + "\n"; } else { result += "failed import file " + afile.getoriginalfilename() + "\n"; } } return result; } @override public boolean readexcelfile(file xlfile) throws ioexception, dataaccessexception, nosuchmethodexception, securityexception { fileinputstream fis = new fileinputstream(xlfile); // finds workbook // instance xlsx // file xssfworkbook myworkbook = new xssfworkbook(fis); // return first sheet // xlsx // workbook boolean success; success = readfunddefinition(myworkbook); myworkbook.close(); return success; } @override @transactional(rollbackfor = exception.class) public boolean readfunddefinition(xssfworkbook myworkbook) throws dataaccessexception, nosuchmethodexception, securityexception { /*here stuff extract data excel initialize administrator, custodian, invcontact , success variables*/ savecontact(administrator); savecontact(custodian); savecontact(invcontact); /*if of 3 invocations savecontact fails, want 3 inserts rollback*/ return success; } @override public void savecontact(personinfo personinfo) throws dataaccessexception, nosuchmethodexception, securityexception { /*a bunch of stuff before line*/ personinfo.copy(personinfodao.store(personinfo)); // <--- transaction fail /*a bunch of stuff after line*/ } } here's interface it:
@controller public interface exceluploader { public @responsebody string handlefileupload(httpservletrequest request, @requestparam commonsmultipartfile[] fileupload) throws dataaccessexception, nosuchmethodexception, securityexception; public boolean readexcelfile(file xlfile) throws ioexception, dataaccessexception, nosuchmethodexception, securityexception; public boolean readfunddefinition(xssfworkbook myworkbook) throws dataaccessexception, nosuchmethodexception, securityexception; public void savecontact(personinfo personinfo, personaddress personaddress, personemail personemail, personphone personphone) throws dataaccessexception, nosuchmethodexception, securityexception; public void readnav(xssfworkbook myworkbook); public boolean isempty(object object, method... methods); } my web-context.xml contains:
<mvc:annotation-driven/> <mvc:default-servlet-handler/> <tx:annotation-driven transaction-manager="transactionmanager" proxy-target-class="true"/> <context:component-scan base-package="ch.oligofunds.oligoworld.web" scoped-proxy="interfaces" /> and dao-context.xml contains:
<context:component-scan base-package="ch.oligofunds.oligoworld.dao" scoped-proxy="interfaces" /> <context:component-scan base-package="ch.oligofunds.oligoworld.security" scoped-proxy="interfaces" /> <tx:annotation-driven transaction-manager="transactionmanager" proxy-target-class="true"/> <context:property-placeholder location="classpath:copyofoligoworld-dao.properties" /> <!-- using atomikos transaction manager --> <bean id="atomikostransactionmanager" class="com.atomikos.icatch.jta.usertransactionmanager" init-method="init" destroy-method="close"> <property name="forceshutdown" value="true" /> <property name="startuptransactionservice" value="true" /> <property name="transactiontimeout" value="60" /> </bean> <bean id="atomikosusertransaction" class="com.atomikos.icatch.jta.usertransactionimp" /> <!-- configure spring framework use jta transactions atomikos --> <bean id="transactionmanager" class="org.springframework.transaction.jta.jtatransactionmanager"> <property name="transactionmanager" ref="atomikostransactionmanager" /> <property name="usertransaction" ref="atomikosusertransaction" /> <property name="transactionsynchronizationname" value="synchronization_on_actual_transaction" /> </bean> <bean name="mysqlds,springsecuritydatasource" class="org.apache.commons.dbcp.basicdatasource" destroy-method="close" > <property name="driverclassname" value="${mysql.connection.driver_class}" /> <property name="username" value="${mysql.connection.username}" /> <property name="password" value="${mysql.connection.password}" /> <property name="url" value="${mysql.connection.url}" /> <property name="maxidle" value="${mysql.minpoolsize}" /> <property name="maxactive" value="${mysql.maxpoolsize}" /> </bean> here's exception thought trigger rollback:
org.springframework.web.util.nestedservletexception: request processing failed; nested exception javax.persistence.persistenceexception: org.hibernate.exception.constraintviolationexception: column 'name' cannot null it's not clear me whether @transactional annotation being picked @ - understanding should, since i'm scanning ch.oligofunds.oligoworld.web package , controller interface annotated @controller. understanding may wrong. :)
any hints? thanks
@transactional on method doesn't have added value internal method call (and class transactional). spring uses proxies , calls object pass thorough proxy.
also code flawed shouldn't catch , swallow exceptions interferes tx support (it relies on transactions determine rollback or not, there never exception hence tries commit).
finally using mysql make sure using table types supports transactions (myisam tables don't have tx support).
i suggest move transactional part (or business logic doing in controller) service. controller (or web layer in general) should thin layer converting incoming request useable service layer , result useable web display.
Comments
Post a Comment