1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
|
---
title: Storage
slug: Storage
tags:
- Interfaces
- SQLite
- Storage
- Toolkit API
translation_of: Mozilla/Tech/XPCOM/Storage
---
<p><strong>Storage</strong> 存储是一个 <a class="external" href="http://www.sqlite.org/">SQLite</a> 数据库API。它可用于受信任的调用者,仅限于扩展和Firefox组件。</p>
<p>For a complete reference of all methods and properties of the database connection interface see <a href="cn/MozIStorageConnection">mozIStorageConnection</a>.</p>
<p>The API is currently "unfrozen," which means it is subject to change at any time. It's likely that the API will change somewhat between Firefox 2 and Firefox 3.</p>
<div class="note"><strong>Note:</strong> Storage is not the same as the <a href="cn/DOM/Storage">DOM:Storage</a> feature which can be used by web pages to store persistent data or the <a href="cn/Session_store_API">Session store API</a> (an <a href="cn/XPCOM">XPCOM</a> storage utility for use by extensions).</div>
<h2 id="Getting_started" name="Getting_started">入门</h2>
<p>This document covers the mozStorage API and some peculiarities of sqlite. It does<em>not</em> cover SQL or "regular" sqlite. You can find some very useful links in the <a href="#See_also"> See also section</a> however. For mozStorage API help, you can post to mozilla.dev.apps.firefox on the news server news.mozilla.org. To report bugs, use <a class="link-https" href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Toolkit&component=Storage">Bugzilla</a> (product "Toolkit", component "Storage").</p>
<p>Here we go then. mozStorage is designed like many other database systems. The overall procedure for use is:</p>
<ul>
<li>Open a connection to the database of your choice.</li>
<li>Create statements to execute on the connection.</li>
<li>Bind parameters to a statement as necessary.</li>
<li>Execute the statement.</li>
<li>Check for errors.</li>
<li>Reset the statement.</li>
</ul>
<h2 id="Opening_a_connection" name="Opening_a_connection">打开一个连接</h2>
<p>C++ users: The storage service's first initialization must be from the main thread. You will get an error if you initialize it the first time from another thread. Therefore, if you want to use the service from a thread, be sure to call getService from the main thread to ensure the service has been created.</p>
<p>C++ example of opening a connection to "asdf.sqlite" in the user's profile directory:</p>
<pre>nsCOMPtr<nsIFile> dbFile;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = dbFile->Append(NS_LITERAL_STRING("asdf.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
mDBService = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBService->OpenDatabase(dbFile, getter_AddRefs(mDBConn));
NS_ENSURE_SUCCESS(rv, rv);
</pre>
<p><code>MOZ_STORAGE_SERVICE_CONTRACTID</code> is defined in <code><a href="https://dxr.mozilla.org/mozilla-central/source/storage/build/mozStorageCID.h" rel="custom">storage/build/mozStorageCID.h</a></code>. It's value is <code>"@mozilla.org/storage/service;1"</code></p>
<p>JavaScript example:</p>
<pre>var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("my_db_file_name.sqlite");
var storageService = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var mDBConn = storageService.openDatabase(file);
</pre>
<dl>
<dd>
<div class="note">Note: The OpenDatabase function is subject to change. It will likely be enhanced/simplified to make it more difficult to get into trouble.</div>
</dd>
</dl>
<p>It may be tempting to give your database a name ending in ".sdb" for <strong>s</strong>qlite <strong>d</strong>ata<strong>b</strong>ase, but this is<em>not recommended.</em> This extension is treated specially by Windows as a known extension for an "Application Compatibility Database" and changes are backed up by the system automatically as part of system restore functionality. This can result in much higher overhead file operations.</p>
<p></p><div class="blockIndicator warning">
<p><strong>Warning:</strong> It may be tempting to give your database a name ending in '.sdb' for <strong>s</strong>qlite <strong>d</strong>ata<strong>b</strong>ase, but this is <em>not recommended.</em> This extension is treated specially by Windows as a known extension for an 'Application Compatibility Database' and changes are backed up by the system automatically as part of system restore functionality. This can result in significantly higher overhead file operation.</p>
</div><p></p>
<h2 id="Statements" name="Statements">关闭一个连接</h2>
<p>To close a connection on which only synchronous transactions were performed, use the <a href="https://developer.mozilla.org/en-US/docs/mozIStorageConnection#close()" title="/en-US/docs/mozIStorageConnection#close()"><code>mozIStorageConnection.close()</code></a> method. If you performed any asynchronous transactions, you should instead use the <a href="https://developer.mozilla.org/en-US/docs/mozIStorageConnection#asyncClose()" title="/en-US/docs/mozIStorageConnection#asyncClose()"><code>mozIStorageConnection.asyncClose()</code></a> method. The latter will allow all ongoing transactions to complete before closing the connection, and will optionally notify you via callback when the connection is closed.</p>
<h2 id="Statements" name="Statements">Statements</h2>
<p>Follow these steps to create and execute SQL statements on your SQLite database. For a complete reference see <a href="cn/MozIStorageStatement">mozIStorageStatement</a>.</p>
<h3 id="Creating_a_statement" name="Creating_a_statement">Creating a statement</h3>
<p>There are two ways to create a statement. If you have no parameters and the statement doesn't return any data, use <code>mozIStorageConnection.executeSimpleSQL</code>.</p>
<pre>C++:
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE foo (a INTEGER)"));
JS:
mDBConn.executeSimpleSQL("CREATE TABLE foo (a INTEGER)");
</pre>
<p>Otherwise, you should prepare a statement using <code>mozIStorageConnection.createStatement</code>:</p>
<pre>C++:
nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM foo WHERE a = ?1"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
JS:
var statement = mDBConn.createStatement("SELECT * FROM foo WHERE a = ?1");
</pre>
<p>This example uses the placeholder "?1" for a parameter to be bound later (see next section).</p>
<p>Once you have a prepared statement, you can bind parameters to it, execute it, and reset it over and over. If you are doing a statement many times, using a precompiled statement will give you a noticable performance improvement because the SQL query doesn't need to be parsed each time.</p>
<p>If you are familiar with sqlite, you may know that prepared statements are invalidated when the schema of the database changes. Fortunately, mozIStorageStatement detects the error and will recompile the statement as needed. Therefore, once you create a statement, you don't need to worry when changing the schema; all statements will continue to transparently work.</p>
<h3 id="Binding_parameters" name="Binding_parameters">Binding parameters</h3>
<p>It is generally best to bind all parameters separately rather than try to construct SQL strings on the fly containing the parameters. Among other things, this prevents SQL injection attacks, since a bound parameter can never be executed as SQL.</p>
<p>You bind parameters to a statement that has placeholders. The placeholders are addressed by index, starting from "?1", then "?2"... You use the statement functions BindXXXParameter(0) BindXXXParameter(1)... to bind to these placeholders.</p>
<dl>
<dd>
<div class="note">Watch out: The indices in the placeholders count from 1. The integers passed to the binding functions count from 0. This means "?1" corresponds to parameter 0, "?2" corresponds to parameters 1, etc.</div>
</dd>
</dl>
<p>You can also use named parameter, like this ":example" instead of "?xx".</p>
<p>A placeholder can appear multiple times in the SQL string and all instances will be replaced with the bound value. Unbound parameters will be interpreted as NULL.</p>
<p>The examples below only use <code>bindUTF8StringParameter()</code> and <code>bindInt32Parameter()</code>. For list of all binding functions see <a href="cn/MozIStorageStatement#Binding_functions">mozIStorageStatement</a>.</p>
<p>C++ example:</p>
<pre>nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM foo WHERE a = ?1 AND b > ?2"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindUTF8StringParameter(0, "hello"); // "hello" will be substituted for "?1"
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt32Parameter(1, 1234); // 1234 will be substituted for "?2"
NS_ENSURE_SUCCESS(rv, rv);
</pre>
<p>JavaScript example:</p>
<pre>var statement = mDBConn.createStatement("SELECT * FROM foo WHERE a = ?1 AND b > ?2");
statement.bindUTF8StringParameter(0, "hello");
statement.bindInt32Parameter(1, 1234);
</pre>
<p>If you use named parameters, you should use the <code>getParameterIndex</code> method to get the index of the named parameter. Here is a JavaScript example:</p>
<pre>var statement = mDBConn.createStatement("SELECT * FROM foo WHERE a = :myfirstparam AND b > :mysecondparam");
var firstidx = statement.getParameterIndex(":myfirstparam");
statement.bindUTF8StringParameter(firstidx, "hello");
var secondidx = statement.getParameterIndex(":mysecondparam");
statement.bindInt32Parameter(secondidx, 1234);
</pre>
<p>You can of course mix named parameters and indexed parameters in a same query:</p>
<pre>var statement = mDBConn.createStatement("SELECT * FROM foo WHERE a = ?1 AND b > :mysecondparam");
statement.bindUTF8StringParameter(0, "hello");
// you can also use
// var firstidx = statement.getParameterIndex("?1");
// statement.bindUTF8StringParameter(firstidx, "hello");
var secondidx = statement.getParameterIndex(":mysecondparam");
statement.bindInt32Parameter(secondidx, 1234);
</pre>
<p>If you want to use a <code>WHERE</code> clause with an <code>IN ( value-list )</code> expression, Bindings won't work. Construct a string instead. If you're not handling user input it's no safety concern:</p>
<pre>var ids = "3,21,72,89";
var sql = "DELETE FROM table WHERE id IN ( "+ ids +" )";
</pre>
<h3 id="Executing_a_statement" name="Executing_a_statement">Executing a statement</h3>
<p>The main way to execute a statement is with <code>mozIStorageStatement.executeStep</code>. This function allows you to enumerate all the result rows your statement produces, and will notify you when there are no more results.</p>
<p>After a call to <code>executeStep</code>, you <strong>use the appropriate getter function</strong> in <a href="cn/MozIStorageValueArray">mozIStorageValueArray</a> to get the values in a result row (mozIStorageStatement implements mozIStorageValueArray). The example below only uses <code>getInt32()</code>.</p>
<p>You can get the type of a value from <code>mozIStorageValueArray.getTypeOfIndex</code>, which returns the type of the specified column. Be careful: sqlite is not a typed database. Any type can be put into any cell, regardless of the type declared for the column. If you request a different type, sqlite will do its best to convert them, and will do some default value if it is impossible. Therefore, it is impossible to get type errors, but you may get weird data out.</p>
<p>C++ code can also use <code>AsInt32</code>, <code>AsDouble</code>, etc. functions which return the value as a more convenient C++ return value. Watch out, though, because you won't get any errors if your index is invalid. Other errors are impossible, because sqlite will always convert types, even if they don't make sense.</p>
<p>C++ example:</p>
<pre>PRBool hasMoreData;
while (NS_SUCCEEDED(statement->ExecuteStep(&hasMoreData)) && hasMoreData) {
PRInt32 value = statement->AsInt32(0);
// use the value...
}
</pre>
<p>Javascript example:</p>
<pre>while (statement.executeStep()) {
var value = statement.getInt32(0); // use the correct function!
// use the value...
}
</pre>
<p><code>mozIStorageStatement.execute()</code> is a convenience function for when you are getting no data out of the statement. It steps the statement once and resets it. This can be useful for insert statements because it really cleans up the code:</p>
<pre>var statement = mDBConn.createStatement("INSERT INTO my_table VALUES (?1)");
statement.bindInt32Parameter(52);
statement.execute();
</pre>
<p>This <img alt="Image:TTRW2.zip"> is a simple, but complete, JavaScript and XUL example of how you run an SQL SELECT against a database.</p>
<h3 id="Resetting_a_statement" name="Resetting_a_statement">Resetting a statement</h3>
<p>It is important to reset statements that are no longer being used. Un-reset write statements will keep a lock on the tables and will prevent other statements from accessing it. Un-reset read statements will prevent writes.</p>
<p>When the statement object is freed, its corresponding database statement is closed. If you are using C++ and you know that all references will be destroyed, you don't have to explicitly reset the statement. Also, if you use <code>mozIStorageStatement.execute()</code>, you don't need to explicitly reset the statement; this function will reset it for you. Otherwise, call <code>mozIStorageStatement.reset()</code>.</p>
<p>JavaScript callers should ensure that statements are reset. Be particularly careful about exceptions. You will want to make sure to reset your statements even if an exception is fired, or subsequent access to the database may not be possible. Resetting a statement is relatively lightweight, and nothing bad happens if it's already reset, so don't worry about unnecessary resets.</p>
<pre>var statement = connection.createStatement(...);
try {
// use the statement...
} finally {
statement.reset();
}
</pre>
<p>C++ callers must do the same. There is a scoped object in <code><a href="https://dxr.mozilla.org/mozilla-central/source/storage/public/mozStorageHelper.h" rel="custom">storage/public/mozStorageHelper.h</a></code> called mozStorageStatementScoper which will ensure that a given statement is reset when the enclosing scope is exited. It is hightly recommended that you use this object if possible.</p>
<pre>void someClass::someFunction()
{
mozStorageStatementScoper scoper(mStatement)
// use the statement
}
</pre>
<h2 id="Last_insert_id" name="Last_insert_id">Last insert id</h2>
<p>Use the <code>lastInsertRowID</code> property on the connection to get the id (rowid) from the last <code>INSERT</code> operation on the db.<br>
This is useful if you have a column in your table set to <code>INTEGER PRIMARY KEY</code> or <code>INTEGER PRIMARY KEY AUTOINCREMENT</code> in which case SQLite automatically assigns a value for each row inserted if you don't provide one.<a class="external" href="http://www.sqlite.org/faq.html#q1"> The returned value is of type <code>number</code> in JS and <code>long long</code> in C++. </a></p>
<p><a class="external" href="http://www.sqlite.org/faq.html#q1"><code>lastInsertRowID</code> JS example: </a></p>
<pre><a class="external" href="http://www.sqlite.org/faq.html#q1">var sql = "INSERT INTO contacts_table (number_col, name_col) VALUES (?1, ?2)"
var statement = mDBConn.createStatement(sql);
statement.bindUTF8StringParameter(0, number);
statement.bindUTF8StringParameter(1, name);
statement.execute();
statement.reset();
var rowid = mDBConn.lastInsertRowID;
</a></pre>
<h2 id="Transactions" name="Transactions"><a class="external" href="http://www.sqlite.org/faq.html#q1">Transactions </a></h2>
<p><a class="external" href="http://www.sqlite.org/faq.html#q1">mozIStorageConnection has functions for beginning and ending transactions. If you do not explicitly use transactions, an implicit transaction will be created for you for each statement. This has major performance implications. There is overhead for each transaction, especially for commits. You will therefore see a large performance win when you are doing multiple statements in a row if you put them in a transaction. See </a><a href="cn/Storage/Performance">Storage:Performance</a> for more performance information.</p>
<p>The major difference between other database systems is that sqlite does not support nested transactions. This means that once a transaction is open, you can not open another transaction. You can check <code>mozIStorageConnection.transactionInProgress</code> to see if a transaction is currently in progress.</p>
<p>You can also just execute "BEGIN TRANSACTION" and "END TRANSACTION" directly as SQL statements (this is what the connection does when you call the functions). However, use of <code>mozIStorageConnection.beginTransaction</code> and related functions are<em>strongly</em> recommended because it stores transaction state in the connection. Otherwise, the attribute <code>transactionInProgress</code> will have the wrong value.</p>
<p>sqlite has several types of transactions:</p>
<ul>
<li>mozIStorageConnection.TRANSACTION_DEFERRED: The default. The database lock is acquired when needed (usually the first time you execute a statement in the transaction).</li>
</ul>
<ul>
<li>mozIStorageConnection.TRANSACTION_IMMEDIATE: Get a read lock on the database immediately.</li>
</ul>
<ul>
<li>mozIStorageConnection.TRANSACTION_EXCLUSIVE: Get a write lock on the database immediately.</li>
</ul>
<p>You can pass this type of transaction to <code>mozIStorageConnection.beginTransactionAs</code> to determine what kind of transaction you need. Keep in mind that if another transaction has already started, this operation will not succeed. Generally, the default TRANSACTION_DEFERRED type is sufficient and you shouldn't use the other types unless you really know why you need them. For more information, see the sqlite documentation about <a class="external" href="http://www.sqlite.org/lang_transaction.html">BEGIN TRANSACTION</a> and <a class="external" href="http://www.sqlite.org/lockingv3.html">locking</a>.</p>
<pre>var ourTransaction = false;
if (!mDBConn.transactionInProgress) {
ourTransaction = true;
mDBConn.beginTransactionAs(mDBConn.TRANSACTION_DEFERRED);
}
// ... use the connection ...
if (ourTransaction)
mDBConn.commitTransaction();
</pre>
<p>From C++ code, you can use the mozStorageTransaction helper class defined in <code><a href="https://dxr.mozilla.org/mozilla-central/source/storage/public/mozStorageHelper.h" rel="custom">storage/public/mozStorageHelper.h</a></code>. This class will begin a transaction of the specified type on the specified connection when it comes into scope, and will either commit or rollback the transaction when it goes out of scope. If a transaction is already in progress, the transaction helper class will not do anything.</p>
<p>It also has functions for explicitly committing. The typical use is that you create the class defaulting to rollback, and then explicitly commit the transaction when processing has succeeded:</p>
<pre>nsresult someFunction()
{
// deferred transaction (the default) with rollback on failure
mozStorageTransaction transaction(mDBConn, PR_FALSE);
// ... use the connection ...
// everything succeeded, now explicitly commit
return transaction.Commit();
}
</pre>
<h2 id="How_to_corrupt_your_database" name="How_to_corrupt_your_database">How to corrupt your database</h2>
<ul>
<li>Read this document: <a class="external" href="http://www.sqlite.org/lockingv3.html">File locking and concurrency in sqlite version 3</a>, especially the section on corruption.</li>
</ul>
<ul>
<li>Open more than one connection to the same file with names that aren't exactly the same as determined by <code>strcmp</code>. This includes "my.db" and "../dir/my.db" or, on Windows (case-insensitive) "my.db" and "My.db". Sqlite tries to handle many of these cases, but you shouldn't count on it.</li>
</ul>
<ul>
<li>Access a database from a symbolic or hard link.</li>
</ul>
<ul>
<li>Open connections to the same database from more than one thread (see "Thread safety" below).</li>
</ul>
<ul>
<li>Access a connection or statement from more than one thread (see "Thread safety" below).</li>
</ul>
<ul>
<li>Open the database from an external program while it is open in Mozilla. Our caching breaks the normal file-locking in sqlite that allows this to be done safely.</li>
</ul>
<h2 id="SQLite_Locking" name="SQLite_Locking">SQLite Locking</h2>
<p>SQLite locks the entire database; that is, any active readers will cause an attempt to write to return SQLITE_BUSY, and an active writer will cause any attempt to read to return SQLITE_BUSY. A statement is considered active from the first step() until reset() is called. execute() calls step() and reset() in one go. A common problem is forgetting to reset() a statement after you've finished step()'ing through.</p>
<p>While a given SQLite connection is capable of having multiple statements open, its locking model limits what these statements can do concurrently (reading or writing). It is in fact possible for multiple statements to be actively reading at one time. It is not possible, however, for multiple statements to be reading and writing at one time<em>on the same table</em> -- even if they are derived from the same connection.</p>
<p>SQLite has a two-tiered locking model: connection level and table level. Most people are familiar with the connection (database) level locking: multiple readers but only one writer. The table-level (B-Tree) locks are what can sometimes be confusing. (Internally, each table in the database has its own B-Tree, so "table" and "B-Tree" are technically synonymous).</p>
<h3 id="Table-level_locks" name="Table-level_locks">Table-level locks</h3>
<p>You would think that if you have only one connection, and it locks the database for writing, you could use multiple statements to do whatever you want. Not entirely. You must be aware of table-level (B-Tree) locks, which are maintained by statement handles traversing the database (i.e. open SELECT statements).</p>
<p>The general rule is this: a statement handle may <strong>not</strong> modify a table (B-Tree) which other statement handles are reading (have open cursors on) -- even if that statement handle shares the same connection (transaction context, database lock, etc.) with the other statement handles.<em>Attempts to do so will still block (or return SQLITE_BUSY)</em> .</p>
<p>This problem often crops up when you attempt to iterate over a table with one statement and modify records within it using another statement. This will not work (or carries a high probability of not working, depending on the optimizer's involvement (see below)). The modifying statement will block because the reading statement has an open cursor on the table.</p>
<h3 id="Working_around_locking_problems" name="Working_around_locking_problems">Working around locking problems</h3>
<p>The solution is to follow (1) as described above. Theoretically, (2) actually shouldn't work with SQLite 3.x. In this scenario, database locks come into play (with multiple connections) in addition to table locks. Connection 2 (modifying connection) will not be able to modify (write to) the database while the Connection 1 (reading connection) is reading it. Connection 2 will require an exclusive lock to execute a modifying SQL command, which it cannot get as long as Connection 1 has active statements reading the database (Connection 1 has a shared read lock during this time which prohibits any other connections from getting an exclusive lock).</p>
<p>Another option is to use a temporary table. Create a temporary table containing the results of the table of interest, iterate over it (putting the reading statement's table lock on the temp table) and then the modifing statement can make changes to the real table without any problem. This can be done with statements derived from a single connection (transaction context). This scenario sometimes happens behind the scenes anyway as ORDER BY can produce temporary tables internally. However, it is not safe to assume that the optimizer will do this in all cases. Explicitly creating a temporary table is only safe way to do perform this latter option.</p>
<h2 id="Thread_safety" name="Thread_safety">Thread safety</h2>
<p>The mozStorage service and sqlite are threadsafe. However, no other mozStorage or sqlite objects or operations are threadsafe.</p>
<ul>
<li>The storage service must be created on the main thread. If you want to access the service from another thread, you should be sure that you call getService from the main thread ahead of time.</li>
</ul>
<ul>
<li>You can not access a connection or statement from multiple threads. These storage objects are not threadsafe, and the sqlite representations of them are not thread safe either. Even if you do locking and ensure that only one thread is doing something at once, there may be problems. This case hasn't been tested, and there may be some internal per-thread state in sqlite. It is strongly advised that you don't do this.</li>
</ul>
<ul>
<li>You can not access a single database from multiple connections from different threads. Normally, sqlite allows this. However, we do <code>sqlite3_enable_shared_cache(1);</code> (see <a class="external" href="http://www.sqlite.org/sharedcache.html">sqlite shared-cache mode</a>) which makes multiple connections share the same cache. This is important for performance. However, there is no lock for cache access, meaning it will break if you use if from more than one thread.</li>
</ul>
<p>It's worth noting, however, that authors of JavaScript browser extensions are less impacted by these restrictions than it might first appear. If a database is created and used exclusively from within JavaScript, thread safety usually will not be an issue. SpiderMonkey (the JavaScript engine run within Firefox) executes JavaScript from a single persistent thread, except when the JavaScript runs in a different thread or is executed from a callback made on a different thread (e.g. via some networking or stream interfaces). Barring incorrect use of multi-threaded JavaScript, problems should occur only if a database already in use by a non-JavaScript, system-level thread is accessed through mozStorage.</p>
<h2 id="See_also" name="See_also">See also</h2>
<ul>
<li><a href="cn/MozIStorageConnection">mozIStorageConnection</a> Database connection to a specific file or in-memory data storage</li>
<li><a href="cn/MozIStorageStatement">mozIStorageStatement</a> Create and execute SQL statements on a SQLite database.</li>
<li><a href="cn/MozIStorageValueArray">mozIStorageValueArray</a> Wraps an array of SQL values, such as a result row.</li>
<li><a href="cn/MozIStorageFunction">mozIStorageFunction</a> Create a new SQLite function.</li>
<li><a href="cn/MozIStorageAggregateFunction">mozIStorageAggregateFunction</a> Create a new SQLite aggregate function.</li>
<li><a href="cn/MozIStorageProgressHandler">mozIStorageProgressHandler</a> Monitor progress during the execution of a statement.</li>
<li><a href="cn/MozIStorageStatementWrapper">mozIStorageStatementWrapper</a> Storage statement wrapper</li>
</ul>
<ul>
<li><a href="cn/Storage/Performance">Storage:Performance</a> How to get your database connection performing well.</li>
<li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/3072">Storage Inspector Extension</a> Makes it easy to view any sqlite database files in the current profile.</li>
<li><a class="external" href="http://www.sqlite.org/lang.html">SQLite Syntax</a> Query language understood by SQLite</li>
<li><a class="external" href="http://sqlitebrowser.sourceforge.net/">SQLite Database Browser</a> is a capable free tool available for many platforms. It can be handy for examining existing databases and testing SQL statements.</li>
<li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/5817">SQLite Manager Extension</a> helps manage sqlite database files on your computer.</li>
</ul>
<div class="noinclude"> </div>
<p></p>
|