xavierlacot / joli.js

joli.js is an Activerecord-like javascript ORM, particularly suited for being used in the Appcelerator Titanium Mobile framework.
MIT License
267 stars 60 forks source link

close() not being called #24

Closed johnnnysc22 closed 12 years ago

johnnnysc22 commented 12 years ago

It looks like the database is never closing. In Android i am getting this error after about 5 seconds from me running a query:

close() was never explicitly called on database '/data/data/com.tb.test/databases/db10' [ERROR][Database(18834)] android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here [ERROR][Database(18834)] at android.database.sqlite.SQLiteDatabase.(SQLiteDatabase.java:1847) [ERROR][Database(18834)] at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820) [ERROR][Database(18834)] at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:854) [ERROR][Database(18834)] at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:847) [ERROR][Database(18834)] at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:547) [ERROR][Database(18834)] at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203) [ERROR][Database(18834)] at ti.modules.titanium.database.DatabaseModule.open(DatabaseModule.java:72) [ERROR][Database(18834)] at org.appcelerator.kroll.runtime.v8.V8Runtime.nativeRunModule(Native Method) [ERROR][Database(18834)] at org.appcelerator.kroll.runtime.v8.V8Runtime.doRunModule(V8Runtime.java:146) [ERROR][Database(18834)] at org.appcelerator.kroll.KrollRuntime.handleMessage(KrollRuntime.java:267) [ERROR][Database(18834)] at org.appcelerator.kroll.runtime.v8.V8Runtime.handleMessage(V8Runtime.java:172) [ERROR][Database(18834)] at android.os.Handler.dispatchMessage(Handler.java:95) [ERROR][Database(18834)] at android.os.Looper.loop(Looper.java:130) [ERROR][Database(18834)] at org.appcelerator.kroll.KrollRuntime$KrollRuntimeThread.run(KrollRuntime.java:104)

Here is my code :

joli = require('/lib/joli').connect('db10');

var profiles = new joli.model({
  table:    'profiles',
  columns:  {
    id:                 'INTEGER PRIMARY KEY AUTOINCREMENT',
    name:               'TEXT',
    orm:        'INTEGER'
  }
});

joli.models.initialize();

var q = new joli.query()
    .select('*')
    .from('profiles')
    .execute();
I get the records I want so everything is setup correctly.  I just thought under the guidelines of the titanium api you should be opening and closing your database connection on each query. You don't want to just leave the connection open.  
xavierlacot commented 12 years ago

Hi John,

Could you please give me the link to the guideline of the API which advices that a new connection should be opened on every query? This is really not the case. Just take care to close every opened connection (using the joli.Connection.disconnect() function) before opening a new one.

Cheers,

johnnnysc22 commented 12 years ago

http://docs.appcelerator.com/titanium/2.0/#!/api/Titanium.Database-method-open

It says 'Always close the database after use.' I'm pretty new to using the database portion in appcelerator so i took it as i open a connection, run my functions and then close the connection.

I could be wrong, but the fact that android is throwing an error about not closing the connection makes me think i'm not.

xavierlacot commented 12 years ago

"Always close the database after use." means that once you have runned the querie(s) that you have to run, you must close the database (ie., before opening it again). This can be done with joli.js using the disconnect() method.

joli.js does not automatically close the database after each request. First, this would be time-consuming, and there are situations where you want to run several queries with the same database connection (transactions, etc.).

In order to help you debug the thing, please search in you application if there are several occurrences of the fdatabase connection (ie., are there several places where you write require('path/to/joli').connect('your_database_name')?). There usually should be only one single place in your application where you open resources like the database connection. If not, try to refactor your code in order to open connections at one single place. If this is not possible, please take care of all the opened connections, and manually close them before opening a new connection.

johnnnysc22 commented 12 years ago

How would this work for a commonJS application. I need to require joli on each .js file i am using (custom tabs). Would i only use the var joli = require('path/to/joli').connect('your_database_name') once and then on all my other js files only use var joli = require('path/to/joli')?

xavierlacot commented 12 years ago

In my applications, I create an instance of joli.js at the start of the application (in the main app.js file), and pass it to all the other commonjs modules of the application. Please have a look at the GouvCamp mobile application, which uses joli.js.

xavierlacot commented 12 years ago

Please note that the way you use jolijs will change depending on the platform:

On iOS, you can create an instance of jolijs in the main app.jsfile :

    var joli = require('path/to/joli').connect('your_database_name')

And then, the joli var will be available in all the commonjs modules.

On Android however, global variables are not available in commonJS modules. this is the reason why I pass the instance of jolijs (and other resources, like http clients, helper modules, etc.) in the constructors of the modules :

    // create a dependency container
    var dic = {};

    // load the jolijs library
    dic.joli = require('lib/vendor/joli.js/joli').connect('database_name');

    // create the model
    var Model = require('lib/model/Model');
    var model = new Model(dic);

    // create the tables if they do not exist in the database
    dic.joli.models.initialize();

    // require and open top level UI component
    var HomeWindow = require('ui/HomeWindow');
    new HomeWindow(dic).open();