java - Process REST request to retrieve data via Hibernate in a separate Thread -
we have java, spring, osgi application jersey rest interface.
in setting need send data mobile device running wince cf 3.5 has 4 mib ram per process. means thousand data objects let mdes memory on flow.
to solve problem idea split request.
- initial request query data, split fragments, encode them json, store them on hdd , return how many fragments there are, reference
- followup requests retrieve 1 fragment @ time, fragment size few 100 kib
this should work crappy connection , allow mde request fragments slow , needs to, while still getting same data snap shot.
my idea first request is, query data hibernate criteria scrollable result, scroll end, total results row number way , create answer intital request, while in ground scroll start , process results json files on hard disk.
the whole hibernate stuff should happen in 1 background thread notifies rest-request-thread once provide data results no actual results data.
now read hibernate , multithreading dangerous mix. yet seems me can avoid trouble if hibernate related happinging in background thread.
@path("/1/mde/articles/") @component @scope("prototype") @transactional public class restmdearticlecontroller { private static final logger log = loggerfactory.getlogger(restmdearticlecontroller.class); @context private httpservletrequest request; @autowired private iresultfragmentationcontroller resultfragmentationcontroller; @autowired private ifindmasterdatastrategy masterdatafinder; @autowired private sessionfactory sessionfactory; @path("fragment") @get @produces(mediatype.application_json) public fragmentedresultinfo getallmdearticlesfragmentedthreaded() { final fragmentedresultinfo info = new fragmentedresultinfo(); thread worker = new thread((new runnable() { private fragmentedresultinfo info = null; public runnable setinfo(fragmentedresultinfo info) { this.info = info; return this; } @override public void run() { try { hibernatetemplate template = new hibernatetemplate(sessionfactory, true); template.execute((new hibernatecallback<object>() { private fragmentedresultinfo info = null; ; public hibernatecallback<object> setinfo(fragmentedresultinfo info) { this.info = info; return this; } @override public object doinhibernate(session session) throws hibernateexception, sqlexception { scrollableresults results = masterdatafinder.findarticles(null, new articlefilteroptions<article>(), scrollmode.scroll_insensitive); resultfragmentationcontroller.createfragments(this.info, results, article.class, mdetransferarticle.class); return null; } }).setinfo(info)); } catch (exception e) { logutil.error(log, e, "thread failed {1}", e.getclass().getsimplename()); } { synchronized (info) { info.notify(); } } } }).setinfo(info)); worker.start(); synchronized (info) { try { // wait worker notify (that updated values in info) info.wait(); } catch (interruptedexception e) { logutil.warn(log, e, "waiting thread '{0}' failed interruptedexception", worker.getname()); } } return info; } }
the problem still don't hibernate-session in new thread.
i know how hibernate-session in child thread , if whole setup has chance work @ all. there pitfalls have not yet considered, should aware of? if have better idea how deal on problem (of splitting data up) open well.
edit 1:
i a:
org.springframework.orm.hibernate3.hibernatesystemexception: no hibernate session bound thread, , configuration not allow creation of non-transactional 1 here; nested exception org.hibernate.hibernateexception: no hibernate session bound thread, , configuration not allow creation of non-transactional 1 here
at line in depth of masterdatafinder:
getsessionfactory() .getcurrentsession() .createcriteria(getentityname(entityclass, storagemode)) .setcomment(stringutil.normalize(comment)) .setresulttransformer(distinctrootentityresulttransformer.instance);
it seems me left out vital information. synchronizing master data mobile device in offline/batch modus. mobile device not have connection of time.
while data on mobile device out of date/sync of time, should @ least consistently so. retrieving pages independently give me data belonging different point in time each request. doing select count(*) before retrieving actual data may give me different results if data changed in few milliseconds take.
i got idea of result scrolling post supposedly had hibernate book. data not retrieved. here start of resultfragmentationcontroller:
results.last(); totalresults = results.getrownumber() + 1; totalfragments = bigdecimal.valueof(totalresults).divide(bigdecimal.valueof(fragmentsize), 0, roundingmode.up).intvalue(); info.settotalfragments(totalfragments); info.settotalresults(totalresults); info.setfragmentsize(fragmentsize); info.setstatus(estate.in_progress); synchronized (info) { info.notify(); } // reset results pointer initial position results.beforefirst(); while (results.next()) { ...
the hibernatetemplate
should allow create new hibernate session
because current springsessioncontext
threadlocal
storage has no session bound.
related design, should close scrollableresults
, release database related resources (connection, cursor).
i therefore design this:
the initial request builds command assigned uuid , command passed executorservice processed asynchronously. result of execution cached.
any subsequent request uses same uuid fetch computation result cache. can use
future
client code blocks untile computation over.
the asynchronous block calculating result object must close hibernate session , free database connection resources.
Comments
Post a Comment