java - Spring-MVC : How to ensure multiple users will be able to call a method in sequence -
i working on spring-mvc application in have method updates contents of object. method requires lot of processing , can called multiple users updating same object. how can ensure method gets updated in sequence triggered each user, , none of user has stale data while updating.
service layer method :
@transactional @service private groupnotesserviceimpl implements groupnotesservice{ @override public string editnotewithmap(map<string, object> notemap) { person person = this.personservice.getcurrentlyauthenticateduser(); if ((notemap != null) && (!notemap.isempty())) { int noteid = (integer) notemap.get("id"); // how ensure below object not stale. groupnotes databasenoteobject = this.groupnotesdao.getgroupnotebyid(noteid); { // process map } // update object below : this.groupnotesdao.editgroupnote(databasenoteobject, databasenoteobject.getownedsectionid()); }
dao layer method :
@repository @transactional public class groupnotesdaoimpl implements groupnotesdao { private final sessionfactory sessionfactory; @override public groupnotes editgroupnote(groupnotes mnotes, int msectionid) { session session = this.sessionfactory.getcurrentsession(); session.flush(); // had lock before, started messing around other updates of associated objects. caused getbyid being under lock. // session.buildlockrequest(new lockoptions(lockmode.pessimistic_write)).lock(mnotes); groupsection groupsection = (groupsection) session.get(groupsection.class, msectionid); groupsection.getsectionsnotes().add(mnotes); mnotes.setownednotes(groupsection); groupnotes savedobject = (groupnotes) session.merge(mnotes); session.merge(groupsection); session.flush(); return savedobject; } catch (exception e) { e.printstacktrace(); } return null; } @override public groupnotes getgroupnotebyid(int id) { session session = this.sessionfactory.getcurrentsession(); session.flush(); return (groupnotes) session.get(groupnotes.class, id); } }
root-context.xml :
<context:component-scan base-package="com.tooltank.spring"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.controller"/> </context:component-scan> <context:property-placeholder location="classpath:application.properties"/> <beans:bean id="datasource" class="org.apache.commons.dbcp.basicdatasource" destroy-method="close"> <beans:property name="driverclassname" value="org.postgresql.driver"/> <beans:property name="url" value="jdbc:postgresql://localhost:5432/dbname"/> <beans:property name="username" value="username"/> <beans:property name="password" value="password"/> <beans:property name="removeabandoned" value="true"/> <beans:property name="removeabandonedtimeout" value="20"/> <beans:property name="defaultautocommit" value="false"/> </beans:bean> <!-- hibernate 4 sessionfactory bean definition --> <beans:bean id="hibernate4annotatedsessionfactory" class="org.springframework.orm.hibernate4.localsessionfactorybean"> <beans:property name="datasource" ref="datasource"/> <beans:property name="packagestoscan" value="com.tooltank.spring.model"/> <beans:property name="hibernateproperties"> <beans:props> <beans:prop key="hibernate.dialect">org.hibernate.dialect.postgresql9dialect</beans:prop> <beans:prop key="hibernate.show_sql">false</beans:prop> <!-- <beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop>--> <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop> <beans:prop key="cache.use_second_level_cache">true</beans:prop> <beans:prop key="cache.use_query_cache">true</beans:prop> <beans:prop key="hibernate.order_updates">true</beans:prop> <beans:prop key="show_sql">false</beans:prop> </beans:props> </beans:property> </beans:bean> <beans:bean id="loginserviceimpl" class="com.tooltank.spring.service.loginserviceimpl"/> <task:annotation-driven executor="myexecutor"/> <task:executor id="myexecutor" pool-size="7-42" queue-capacity="11"/> <tx:annotation-driven transaction-manager="transactionmanager"/> <beans:bean id="transactionmanager" class="org.springframework.orm.hibernate4.hibernatetransactionmanager"> <beans:property name="sessionfactory" ref="hibernate4annotatedsessionfactory"/> </beans:bean> <cache:annotation-driven/> <beans:bean id="cachemanager" class="org.springframework.cache.support.simplecachemanager"> <beans:property name="caches"> <beans:set> <beans:bean class="org.springframework.cache.concurrent.concurrentmapcachefactorybean" p:name="person"/> </beans:set> </beans:property> </beans:bean> <!-- appconfiguration spring-data-redis --> <beans:bean id="jedisconnfactory" class="org.springframework.data.redis.connection.jedis.jedisconnectionfactory" p:usepool="true"/> <beans:bean id="redissavetemplate" class="org.springframework.data.redis.core.redistemplate" p:connectionfactory-ref="jedisconnfactory"/> <beans:bean id="redistemplate" class="org.springframework.data.redis.core.redistemplate" p:connectionfactory-ref="jedisconnfactory"/>
thank you.
there several way this.
1. quick way, syncronize it!
by making editnotewithmap() syncronized method, can ensure 1 thread accessing editnotewithmap(). syncronized might not magic want if note can updated somewhere else (other method /other system) , or if worry might cause performance issue.
2. long way, implement locking/version mechanism.
you can create locking/version mechanism on note record. there several way achieve it, 1 example adding version column on note record. prior update, should check if version of record equal version retrieved, , decide whether want retry or fail update.
Comments
Post a Comment