Orsiso
-
Upload
e27 -
Category
Technology
-
view
662 -
download
0
Transcript of Orsiso
![Page 1: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/1.jpg)
Asynchronous SQL in Flex
Jerome Poudevigne
Aureliant
CTO
![Page 2: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/2.jpg)
OrSiSo Adobe AIR Social network aggregator +
multiprotocol chat Facebook, Twitter, Flickr, Friendster,
Yahoo!, MSN, gTalk…
![Page 3: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/3.jpg)
SQLite use by OrSiSo Data comes from the server Stored in SQLite database for fast local
access
![Page 4: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/4.jpg)
UI heavy on SELECT
![Page 5: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/5.jpg)
UI heavy on SELECT
![Page 6: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/6.jpg)
UI heavy on SELECT
![Page 7: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/7.jpg)
UI heavy on SELECT
![Page 8: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/8.jpg)
UI heavy on SELECT
![Page 9: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/9.jpg)
OrSiSo - contention on DB The user is browsing a lot of data
Click on a view icon => UI freeeze on a long SELECT
The data is updated in the background by querying a server 100’s of INSERT staitements =>UI freeze
too
![Page 10: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/10.jpg)
Synchronous cache update
ZZZ….
Dataarrives
Local cacheupdated
Now you can use it again…
![Page 11: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/11.jpg)
Asynchronous : Why ?
“Because synchronous operations execute in the main execution thread, all application functionality (including refreshing the screen and allowing mouse and keyboard interaction) is paused while the database operation or operations are performed.”
For long-running operations this can cause a noticeable pause in the application.
![Page 12: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/12.jpg)
Async data set loading Create a class to send SQL search
query Make this class load chunk by chunk Assign an event every time a chunk is
loaded
![Page 13: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/13.jpg)
public class ListLoader extends ArrayCollection{protected var stmt:SQLStatement = new SQLStatement();protected var result:SQLResult;
public function ListLoader(source:Array=null){ super(source);}
public function start(userCacheConn:SQLConnection):void{(..) stmt.addEventListener(SQLEvent.RESULT, onResult); stmt.text = "SELECT * from c_albums where description <> ''"; stmt.execute(30); dispatchEvent(new CollectionEvent(CollectionEventKind.RESET));}
public function next():void{
if (stmt.executing){
stmt.next(30);}
}
public function onResult(e:SQLEvent):void{ result = stmt.getResult(); dispatchEvent(new CollectionEvent(CollectionEvent.COLLECTION_CHANGE));}
![Page 14: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/14.jpg)
protected var dbReadConn:SQLConnection;protected var theList:ListLoader = new ListLoader();[Bindable] protected var theData:ArrayCollection=new ArrayCollection();
theList.addEventListener(CollectionEvent.COLLECTION_CHANGE,onCollectionChange);theList.addEventListener(CollectionEventKind.RESET, onCollectionReset);
protected function onCollectionChange(e:CollectionEvent):void{
var d:Array = (e.target as ListLoader).data;for (var ii:int=0;ii<d.length;ii++){
theData.addItem(d[ii]);}if (!theList.complete){
theList.next(); // Or use callLater()}
}
trace ("db is opened a-synchronously");theList.start(dbReadConn);
<mx:List height="100%" width="100%" dataProvider="{theData}” itemRenderer="AlbumRenderer" />
![Page 15: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/15.jpg)
Inserting data
![Page 16: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/16.jpg)
Synchronous cache update
ZZZ….
Dataarrives
Local cacheupdated
Now you can use it again…
![Page 17: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/17.jpg)
SQLConnection-synchronous We are used to thattry
{
SQLStatement.exec(“SOME SQL”);
SQLStatement.exec(“MORE SQL”);
}
catch (…)
{
}
![Page 18: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/18.jpg)
Asynchronous
(100’s of XML items)
Dataarrives
Update in the background
User interface never locked
![Page 19: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/19.jpg)
SQLConnection-asynchronous Less familiarStmt.text=“DO SOME SQL”;stmt.addEventListener(COMPLETE, OnNextStep);stmt.execute();…
Function onNextStep(e:SQLEvent){
stmt.text=“DO MORE SQL”stmt.addEventListener(COMPLETE, onDone);stmt.execute();
}Function onDone(e:SQLEvent){
// Whew !}
![Page 20: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/20.jpg)
Issues How can you write 150 insert
statements by using the code above ? What if you need transactions ?
![Page 21: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/21.jpg)
Transactions-asynchronous Naïve 1
Connection.beginTransaction();
Stmt.text=“DO SOME SQL”;stmt.execute();Stmt.text=“DO SOME SQL”;stmt.execute();Stmt.text=“DO SOME SQL”;stmt.execute();
Connection.commit();
Does not work. In Async mode Flex does not guarantee that SQL execution is in the same order as the Flex lines of code…
![Page 22: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/22.jpg)
Transactions-asynchronous Naïve 2Connection.beginTransaction();
Function onStarted(..){ Stmt.text=“DO SOME SQL”; stmt.addEventListener(COMPLETE, OnNextStep); stmt.execute();}
Function onNextStep(e:SQLEvent){ stmt.text=“DO MORE SQL” stmt.addEventListener(COMPLETE, onDone); stmt.execute();}Function onDone(e:SQLEvent){
// Whew !! And what if I had 150 of these… }
![Page 23: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/23.jpg)
A solution : StatementList class
public class StatementList extends EventDispatcher{ public function StatementList(
conn:SQLConnection, statements:Object, withTransaction:Boolean=false )
public function execute ():void
}
Encapsulate a loop in a class
![Page 24: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/24.jpg)
public class StatementList extends EventDispatcher implements ISQLExecutable{public var _execStack:Array = new Array();public function StatementList(
conn:SQLConnection, statements:Object, withTransaction:Boolean=false)
{__execStack.push(statements);}
}
public function execute ():void{
trace ("Beginning transaction",text);_conn.begin(null, new Responder(onBeginTransaction,
onErrorStartingTransaction));}
protected function onBeginTransaction(e:Object=null):void{_ transactionStarted = true; executeNext();}
![Page 25: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/25.jpg)
protected function executeNext():void{
if (_execStack.length > 0){_cStmt = _execStack.shift() as SQLStatement;(..);_cStmt.addEventListener(SQLEvent.RESULT, onResult,false,0,true);_cStmt.execute();}else{
trace ("Done.Committing transaction ",text); _conn.commit(new Responder(onConclude, onCannotCommit));}
}
protected function onResult(e:Object=null):void{
if (e is SQLEvent){ (e.target as EventDispatcher).removeEventListener(SQLEvent.RESULT, onResult);}
executeNext();}
![Page 26: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/26.jpg)
Still having issues…protected function executeNext():void{
if (_execStack.length > 0){_cStmt = _execStack.shift() (..);_cStmt.addEventListener(SQLEvent.RESULT, onResult,false,0,true);_cStmt.execute();}
}
protected function onResult(e:Object=null):void{
executeNext();}
Function onClickListFriends(..){Stmt.text=“SELECT FRIENDS WHERE”;stmt.execute();}
Guaranteed locking…
![Page 27: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/27.jpg)
One level (of abstraction) up… Create an execution queue Everything is IExecutable
package com.aureliant.model.cache{
import flash.events.IEventDispatcher;
public interface IExecutable extends IEventDispatcher{
function execute():void;function get canceled():Boolean;
}}
![Page 28: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/28.jpg)
public class ExecutionQueue{protected var _theQueue:Array = new Array();protected var _current:IExecutable;
public function add(item:IExecutable):void{ _theQueue.push(item);
if (_current == null) //start immediately if empty{ onExecuteNext();}
}protected function onExecuteNext (e:Event=null):void{
if (_current != null){ _current.removeEventListener(StatementListEvent.FINISHED, onExecuteNext); _current = null;}while (_theQueue.length > 0){
var tmp:IExecutable = _theQueue.shift() as IExecutable;if (!tmp.canceled){ _current = tmp; break;}
} if (_current != null) { _current.addEventListener(StatementListEvent.FINISHED, onExecuteNext,false,0,true); _current.execute(); }}}
![Page 29: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/29.jpg)
public function storeAlerts(rawList:Object, responder:IResponder=null):void{
// Create the INSERT statements for the alerts itemsvar saver:StatementList = new StatementList(withTransaction);
for (var ii:int=0;ii<(theList as ArrayCollection).length; ii++){ anItem = (theList as ArrayCollection).getItemAt(ii); saver.addSQL( "INSERT OR IGNORE INTO showedalert(guid,alreadyShowed) values ('"+
anItem.guid+"',0)");}
ExecutionQueue.instance.add(saver); // Put in the queue}
![Page 30: Orsiso](https://reader033.fdocuments.us/reader033/viewer/2022052311/558fc7fe1a28ab7a4e8b47b4/html5/thumbnails/30.jpg)
Demo Questions ?