AIR SQLite的:SQLEvent.RESULT没有发射,但说法是正确执行说法、正确、SQLite、AIR

2023-09-09 21:48:21 作者:师太、亲一个

好了,它看起来喜欢像我在一个陌生的计时问题已经迷迷糊糊......我做了一个快速的SQL包装类执行SQL语句。 .execute后不过()被调用时,SQLEvent.RESULT事件从来没有发射,但在数据库中创建新条目,它应该是。真的非常奇怪的部分是,如果我把一个的setTimeout()只是调用execute()事件触发按预期的方式。我希望我失去了一些东西真的很明显这里...这里是一个链接到一个例子AIR应用程序后: http://www.massivepoint.com/airsqltest/AIRSQL.zip

这里是code到包装类:

如果您在SQLREQUEST类往下看51行,你会看到注释掉setTimeout()方法。为了使一切工作,只是取消注释行..但对我来说这没有任何意义......

任何人有什么想法?我完全难住在这里...

 包com.jac.sqlite
{//包
 进口flash.data.SQLConnection使用;
 进口flash.data.SQLStatement;
 进口flash.events.EventDispatcher使用;
 进口flash.events.SQLErrorEvent;
 进口flash.events.SQLEvent;
 进口flash.utils.setTimeout;

 公共类SQLREQUEST扩展EventDispatcher
 {// SQLREQUEST类

  私人VAR _callback:功能;
  私人VAR _dbConn:的SQLConnection;
  私人VAR _query:字符串;
  私人VAR _params:对象;

  私人VAR _statement:的SQLStatement;


  公共职能SQLREQUEST(回调:功能,连接方式:的SQLConnection,查询:字符串参数:对象= NULL):无效
  {// SQLREQUEST
   跟踪(创建新的SQL请求);
   _callback =回调;
   _dbConn =连接;
   _query =查询;
   _params =参数;


   _statement =新的SQLStatement();
   _statement.sqlConnection = _dbConn;
   _statement.text = _query;

   如果(_params!= NULL)
   {//分配
    对于(VAR参数:字符串中_params)
    {// PARAMS
     跟踪(设置参数:+参数+到+ _params [参数]);
     _statement.parameters [参数] = _params [参数]
    } // PARAMS
   }//分配

   //设置事件
   _statement.addEventListener(SQLEvent.RESULT,handleResult,假,0,真正的);
   _statement.addEventListener(SQLErrorEvent.ERROR,handleError的,假的,0,真正的);
  } // SQLREQUEST

  公共职能startLoad():无效
  {//执行
   _statement.execute();
   //的setTimeout(handleTimeOut,10000);
  }//执行

  // TEMP
  私有函数handleTimeOut():无效
  {// handleTimeOut
   跟踪(执行:+ _statement.executing +/+执行);
  } // handleTimeOut

  私有函数handleResult(E:SQLEvent):无效
  {// handleResult
   跟踪(好SQL请求);
   _callback(E);
   则dispatchEvent(E);
  } // handleResult

  私有函数handleError的(E:SQLErrorEvent):无效
  {// handleError的
   跟踪(SQL错误:+ e.errorID +:+ e.error);
   //则dispatchEvent(E);
  } // handleError的

  公共职能得到执行():布尔
  {//得到执行
   返回_statement.executing;
  } //得到执行

  公共函数来获取查询():字符串{返回_query; }
  公共职能GET语句(){的SQLStatement回报_statement; }

 } // SQLREQUEST类

}//包
 

解决方案

我想你在这里失踪的是垃圾收集。

没有测试你的code,但可能肯定是问题的根源。

  VAR sqlReq:SQLREQUEST =新SQLREQUEST(handleResult,_dbConn,SQL);
sqlReq.startLoad();
 
旧事文摘 美籍华人演奏家形容中国人是 猪 ,老父亲都怒了

参考 sqlReq 是本地的功能,成为unreacheable当函数返回。这使得它收藏。我想一定是有code在AIR运行时,更多的agressively当有涉及SQL连接收集垃圾。因为通常情况下,你会逃脱不存储裁判的对象(至少在一个基于Web的环境下,以我的经验,这是在这样的code中的错误,不过,你只需要在一个坏的一天来体验吧)。

的setTimeout 掩盖这个问题(或基本解决它,虽然在一个意想不到的方式),因为的setTimeout 功能使用定时器内部。运行计时器没有收集。因此,定时器是活蹦乱跳的,并引用了你的 SQLREQUEST 实例,这使得它reacheable,所以,不elligible收集。如果您的数据库调用需要比超时时间,虽然,你回来了同样的情况。

要解决这个问题,存储裁判的对象,并妥善处置它时,你就大功告成了。

修改

另一种选择,如果你不想改变你调用code的工作方式,是存储裁判实例在类范围(即静态),字典的通话时间(本词典建议立即进行删除不的使用弱引用键原因很明显)。

您添加一个隐藏的副作用的方法,它不是一般的好设计的标志,但只要你删除它时,调用数据库完成后(无论succeded与否),你'重安全,所以我认为这个问题是更多的风格比什么都重要。

我的意思是这样的:

 私有静态无功_dict:字典=新词典();

公共职能startLoad():无效
{//执行
    _statement.execute();
    //添加一个自我引用字典这样的实例将不会收集
    //做到这一点,在最后一行,因此,如果我们有一个例外执行,这
    // code将无法运行(或者,如果你想添加一个try / catch,但是这是简单
    //和清洁,国际海事组织
    addToDict();
}//执行

私有函数handleResult(E:SQLEvent):无效
{// handleResult
    //运行任何其他code之前删除的自基准
    //(再次,这是情况下,code后面抛出)
    removeFromDict();
    跟踪(好SQL请求);
    _callback(E);
    则dispatchEvent(E);
} // handleResult

私有函数handleError的(E:SQLErrorEvent):无效
{// handleError的
    //相同的评论,因为handleResult
    removeFromDict();
    跟踪(SQL错误:+ e.errorID +:+ e.error);
    //则dispatchEvent(E);
} // handleError的

私有函数addToDict():无效{
    _dict [这] =真;
}

私有函数removeFromDict():无效{
    如果(_dict [这]){
        删除_dict [这]
    }
}
 

Ok it looks likes like I have stumbled upon a strange timing issue... I made a quick SQL wrapper class for executing sql statements. However after .execute() is called, the SQLEvent.RESULT event is never fired, but the new entry in the DB is created as it should be. The really really odd part is if I put a setTimeout() just after calling execute() the event fires as expected.. I hope I'm missing something really obvious here... Here is a link to an example air app: http://www.massivepoint.com/airsqltest/AIRSQL.zip

And here is the code to the wrapper class:

if you look down at line 51 in the SQLRequest class, you will see the commented out setTimeout() method. To make everything work, just uncomment that line.. but to me this doesn't make any sense...

anyone have any thoughts? I'm totally stumped here...

package com.jac.sqlite 
{//Package
 import flash.data.SQLConnection;
 import flash.data.SQLStatement;
 import flash.events.EventDispatcher;
 import flash.events.SQLErrorEvent;
 import flash.events.SQLEvent;
 import flash.utils.setTimeout;

 public class SQLRequest extends EventDispatcher
 {//SQLRequest Class

  private var _callback:Function;
  private var _dbConn:SQLConnection;
  private var _query:String;
  private var _params:Object;

  private var _statement:SQLStatement;


  public function SQLRequest(callback:Function, connection:SQLConnection, query:String, parameters:Object=null):void 
  {//SQLRequest
   trace("Creating new SQL Request");
   _callback = callback;
   _dbConn = connection;
   _query = query;
   _params = parameters;


   _statement = new SQLStatement();
   _statement.sqlConnection = _dbConn;
   _statement.text = _query;

   if (_params != null)
   {//assign
    for (var param:String in _params)
    {//params
     trace("Setting Param: " + param + " to: " + _params[param]);
     _statement.parameters[param] = _params[param];
    }//params
   }//assign

   //setup events
   _statement.addEventListener(SQLEvent.RESULT, handleResult, false, 0, true);
   _statement.addEventListener(SQLErrorEvent.ERROR, handleError, false, 0, true);
  }//SQLRequest

  public function startLoad():void
  {//execute
   _statement.execute();
   //setTimeout(handleTimeOut, 10000);
  }//execute

  //TEMP
  private function handleTimeOut():void
  {//handleTimeOut
   trace("Executing: " + _statement.executing + " / " + executing);
  }//handleTimeOut

  private function handleResult(e:SQLEvent):void 
  {//handleResult
   trace("Good SQL Request");
   _callback(e);
   dispatchEvent(e);
  }//handleResult

  private function handleError(e:SQLErrorEvent):void 
  {//handleError
   trace("SQL Error: " + e.errorID + ": " + e.error);
   //dispatchEvent(e);
  }//handleError

  public function get executing():Boolean
  {//get executing
   return _statement.executing;
  }//get executing

  public function get query():String { return _query; }
  public function get statement():SQLStatement { return _statement; }

 }//SQLRequest Class

}//Package

解决方案

I think what you're missing here is garbage collection.

Haven't tested your code, but this could certainly be the source of the problem.

var sqlReq:SQLRequest = new SQLRequest(handleResult, _dbConn, sql);
sqlReq.startLoad();

The reference sqlReq is local to the function and becomes unreacheable when the function returns. That makes it collectable. I guess there must be some code in the AIR runtime that collects garbage more agressively when there are sql connections involved. Because generally, you'll get away with not storing a ref to your object (at least in a web based environment, in my experience; this is a bug in such code, nevertheless; you just have to be in a bad day to experience it).

The setTimeout masks this problem (or almost solves it, although in an unintended way), because the setTimeout function uses a Timer internally. Running timers are not collected. So, the timer is alive and kicking and has a reference to your SQLRequest instance, which makes it reacheable, and so, not elligible for collection. If your DB call takes longer than the timeout though, you're back in the same situation.

To solve this, store a ref to the object and dispose it properly when you're done.

Edit

Another option, if you don't want to change the way you calling code works, is storing a ref to the instance in a class-scoped (i.e. static) dictionary for the duration of the call (this dictionary shoul not use weak referenced keys for obvious reasons).

You are adding a hidden side effect to your method, which is not a sign of good design in general, but as long as you remove it when the call to the DB is finished (whether it succeded or not), you're safe, so I think the problem is more of style than anything else.

What I mean is something like this:

private static var _dict:Dictionary = new Dictionary();

public function startLoad():void
{//execute
    _statement.execute();
    //  add a self reference to dict so the instance won't be collected
    //  do this in the last line, so if we have an exception in execute, this
    //  code will not run (or add a try/catch if you want, but this is simpler
    //  and cleaner, IMO
    addToDict();
}//execute

private function handleResult(e:SQLEvent):void 
{//handleResult
    //  remove the self reference before running any other code
    //  (again, this is in case the code that follows throws)
    removeFromDict();
    trace("Good SQL Request");
    _callback(e);
    dispatchEvent(e);
}//handleResult

private function handleError(e:SQLErrorEvent):void 
{//handleError
    //  same comment as handleResult
    removeFromDict();
    trace("SQL Error: " + e.errorID + ": " + e.error);
    //dispatchEvent(e);
}//handleError

private function addToDict():void {
    _dict[this] = true;
}

private function removeFromDict():void {
    if(_dict[this]) {
        delete _dict[this];
    }
}