mm_sqlite 1.3.2 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/README_EN.md +293 -0
- package/db.js +890 -161
- package/eslint.config.js +235 -0
- package/index.js +910 -169
- package/link_model.js +129 -0
- package/package.json +50 -36
- package/sql.js +1972 -0
- package/sql.json +56 -0
- package/test_backup.js +78 -0
- package/test_db/test_basic.db +0 -0
- package/test_db/test_core_methods.db +0 -0
- package/test_db/test_db.db +0 -0
- package/test_db/test_sql.db +0 -0
- package/test_sql_functions.js +86 -0
- package/test_sqlite.js +104 -0
- package/config.json +0 -0
- package/db/mm.db +0 -0
- package/test.js +0 -84
package/index.js
CHANGED
|
@@ -1,196 +1,937 @@
|
|
|
1
|
-
require('mm_expand');
|
|
2
1
|
const sqlite3 = require('sqlite3').verbose();
|
|
3
2
|
const {
|
|
4
|
-
|
|
3
|
+
DB
|
|
5
4
|
} = require('./db');
|
|
5
|
+
const { Base } = require('mm_expand');
|
|
6
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
|
-
_this.error = {
|
|
70
|
-
code: err.errno,
|
|
71
|
-
message: $.info(err).between('Error: ', ']')
|
|
72
|
-
};
|
|
73
|
-
resolve(rows);
|
|
74
|
-
} else {
|
|
75
|
-
_this.error = undefined;
|
|
76
|
-
resolve(rows);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @description 增删改sql
|
|
84
|
-
* @param {String} sql 查询参
|
|
85
|
-
* @param {Array} val 替换值
|
|
86
|
-
* @return {Promise|Array} 异步构造器, 当await时返回执行结果
|
|
87
|
-
*/
|
|
88
|
-
this.exec = function(sql) {
|
|
89
|
-
var _this = this;
|
|
90
|
-
this.sql = sql;
|
|
91
|
-
// 返回一个 Promise
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
$this.exec(sql, function(err, rows) {
|
|
94
|
-
if (err) {
|
|
95
|
-
// reject(err);
|
|
96
|
-
_this.error = {
|
|
97
|
-
code: err.errno,
|
|
98
|
-
message: $.info(err).between('Error: ', ']')
|
|
99
|
-
};
|
|
100
|
-
resolve(false);
|
|
101
|
-
} else {
|
|
102
|
-
_this.error = undefined;
|
|
103
|
-
resolve(true);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @description 获取数据库管理器
|
|
111
|
-
*/
|
|
112
|
-
this.db = function() {
|
|
113
|
-
return new DB($this.config.database, $this.run, $this.exec);
|
|
114
|
-
};
|
|
115
|
-
}
|
|
7
|
+
/**
|
|
8
|
+
* SQLite数据库操作类
|
|
9
|
+
* @class SQLite
|
|
10
|
+
* @augments Base
|
|
11
|
+
*/
|
|
12
|
+
class SQLite extends Base {
|
|
13
|
+
/**
|
|
14
|
+
* 默认配置
|
|
15
|
+
*/
|
|
16
|
+
static config = {
|
|
17
|
+
dir: './db/'.fullname(),
|
|
18
|
+
user: 'root',
|
|
19
|
+
password: '',
|
|
20
|
+
database: 'mm',
|
|
21
|
+
charset: 'utf8mb4',
|
|
22
|
+
timezone: '+08:00',
|
|
23
|
+
connect_timeout: 20000,
|
|
24
|
+
acquire_timeout: 20000,
|
|
25
|
+
query_timeout: 20000,
|
|
26
|
+
connection_limit: 500,
|
|
27
|
+
queue_limit: 0,
|
|
28
|
+
enable_keep_alive: true,
|
|
29
|
+
keep_alive_initial_delay: 10000,
|
|
30
|
+
enable_reconnect: true,
|
|
31
|
+
reconnect_interval: 1000,
|
|
32
|
+
max_reconnect_attempts: 5,
|
|
33
|
+
wait_for_connections: true,
|
|
34
|
+
// 连接池相关配置
|
|
35
|
+
pool_min: 1,
|
|
36
|
+
pool_max: 5,
|
|
37
|
+
pool_acquire_timeout: 30000,
|
|
38
|
+
pool_idle_timeout: 60000,
|
|
39
|
+
pool_reap_interval: 1000
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 构造函数
|
|
44
|
+
* @param {object} config - 配置对象
|
|
45
|
+
*/
|
|
46
|
+
constructor(config) {
|
|
47
|
+
const merged_cfg = { ...SQLite.config, ...config || {}};
|
|
48
|
+
super(merged_cfg);
|
|
49
|
+
|
|
50
|
+
this.config = merged_cfg;
|
|
51
|
+
this._connection = null;
|
|
52
|
+
this._pool = null;
|
|
53
|
+
this._status = 'closed';
|
|
54
|
+
this._last_connect_time = 0;
|
|
55
|
+
this._reconnecting = false;
|
|
56
|
+
this._is_inited = false;
|
|
57
|
+
this._is_destroyed = false;
|
|
58
|
+
this._db = null;
|
|
59
|
+
this._open = false;
|
|
60
|
+
this._conn_retry_count = 0;
|
|
61
|
+
|
|
62
|
+
// 连接池相关属性
|
|
63
|
+
this._use_pool = this.config.connection_limit > 1;
|
|
64
|
+
this._pool_connections = [];
|
|
65
|
+
this._pool_available = [];
|
|
66
|
+
this._pool_waiting = [];
|
|
67
|
+
this._pool_reaper = null;
|
|
68
|
+
}
|
|
116
69
|
}
|
|
117
70
|
|
|
118
71
|
/**
|
|
119
|
-
*
|
|
120
|
-
* @
|
|
72
|
+
* 初始化服务
|
|
73
|
+
* @returns {Promise<void>}
|
|
121
74
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
75
|
+
SQLite.prototype._initService = async function () {
|
|
76
|
+
if (this._is_inited) {
|
|
77
|
+
this.log('warn', 'SQLite服务已初始化');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
this.log('debug', '初始化SQLite服务', { config: this.config });
|
|
83
|
+
this._is_inited = true;
|
|
84
|
+
this.log('debug', 'SQLite服务初始化完成');
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.log('error', 'SQLite服务初始化失败', error);
|
|
87
|
+
}
|
|
131
88
|
};
|
|
132
89
|
|
|
133
90
|
/**
|
|
134
|
-
*
|
|
91
|
+
* 获取数据库文件名
|
|
92
|
+
* @returns {string} 数据库文件名
|
|
135
93
|
*/
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
_this.error = {
|
|
144
|
-
code: err.errno,
|
|
145
|
-
message: $.info(err).between('Error: ', ']')
|
|
146
|
-
};
|
|
147
|
-
} else {
|
|
148
|
-
_this.error = undefined;
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
94
|
+
SQLite.prototype._getDbFilename = function () {
|
|
95
|
+
var file = this.config.database;
|
|
96
|
+
if (file.indexOf('.') === -1) {
|
|
97
|
+
file += '.db';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return file.fullname(this.config.dir);
|
|
152
101
|
};
|
|
102
|
+
|
|
153
103
|
/**
|
|
154
|
-
*
|
|
104
|
+
* 内部打开数据库连接
|
|
105
|
+
* @private
|
|
106
|
+
* @returns {Promise<void>}
|
|
155
107
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
108
|
+
SQLite.prototype._openInternal = async function () {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
this._db = new sqlite3.Database(this._getDbFilename(), (err) => {
|
|
111
|
+
if (err) {
|
|
112
|
+
reject(err);
|
|
113
|
+
} else {
|
|
114
|
+
resolve();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
161
118
|
};
|
|
162
119
|
|
|
163
|
-
|
|
164
|
-
|
|
120
|
+
/**
|
|
121
|
+
* 打开数据库连接
|
|
122
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
123
|
+
* @returns {Promise<boolean>}
|
|
124
|
+
* @throws {TypeError} 当timeout参数无效时
|
|
125
|
+
*/
|
|
126
|
+
SQLite.prototype.open = async function (timeout) {
|
|
127
|
+
// 参数校验
|
|
128
|
+
if (timeout !== undefined && typeof timeout !== 'number') {
|
|
129
|
+
throw new TypeError('timeout must be number');
|
|
130
|
+
}
|
|
165
131
|
|
|
132
|
+
if (this._status === 'connected' || this._status === 'connecting') {
|
|
133
|
+
this.log('warn', '数据库连接已存在或正在连接中');
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
166
136
|
|
|
167
|
-
|
|
137
|
+
const connect_timeout = timeout || this.config.connect_timeout || 10000;
|
|
138
|
+
this._status = 'connecting';
|
|
168
139
|
|
|
140
|
+
try {
|
|
141
|
+
this.config.dir.addDir();
|
|
142
|
+
if (this._use_pool) {
|
|
143
|
+
// 使用连接池模式
|
|
144
|
+
await this._initPool();
|
|
145
|
+
this._last_connect_time = Date.now();
|
|
146
|
+
this._status = 'connected';
|
|
147
|
+
this.log('info', '数据库连接池初始化成功', {
|
|
148
|
+
dir: this.config.dir,
|
|
149
|
+
database: this.config.database,
|
|
150
|
+
pool_min: this.config.pool_min,
|
|
151
|
+
pool_max: this.config.pool_max
|
|
152
|
+
});
|
|
153
|
+
return true;
|
|
154
|
+
} else {
|
|
155
|
+
// 使用单连接模式
|
|
156
|
+
const conn_promise = this._openInternal();
|
|
157
|
+
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
158
|
+
setTimeout(() => {
|
|
159
|
+
reject(new Error(`数据库连接超时(${connect_timeout}ms)`));
|
|
160
|
+
}, connect_timeout);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
await Promise.race([conn_promise, timeout_promise]);
|
|
165
|
+
|
|
166
|
+
this._last_connect_time = Date.now();
|
|
167
|
+
this._status = 'connected';
|
|
168
|
+
this.log('info', '数据库连接成功', {
|
|
169
|
+
dir: this.config.dir,
|
|
170
|
+
database: this.config.database
|
|
171
|
+
});
|
|
172
|
+
return true;
|
|
173
|
+
} catch (connection_err) {
|
|
174
|
+
this.log('error', '连接过程错误详情', connection_err);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
this._status = 'closed';
|
|
179
|
+
this.log('error', '数据库连接失败', err);
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
169
183
|
|
|
170
184
|
/**
|
|
171
|
-
*
|
|
185
|
+
* 关闭数据库连接
|
|
186
|
+
* @returns {Promise<boolean>}
|
|
172
187
|
*/
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
SQLite.prototype.close = function () {
|
|
189
|
+
if (this._status !== 'connected') {
|
|
190
|
+
this.log('warn', '数据库连接未建立');
|
|
191
|
+
return Promise.resolve(false);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return new Promise((resolve) => {
|
|
195
|
+
try {
|
|
196
|
+
if (this._use_pool) {
|
|
197
|
+
// 关闭连接池
|
|
198
|
+
this._closePool();
|
|
199
|
+
this._db = null;
|
|
200
|
+
this._open = false;
|
|
201
|
+
this._status = 'closed';
|
|
202
|
+
this.log('info', '数据库连接池已关闭');
|
|
203
|
+
resolve(true);
|
|
204
|
+
} else if (this._db) {
|
|
205
|
+
// 单连接模式
|
|
206
|
+
this.log('debug', '关闭数据库连接');
|
|
207
|
+
this._db.close((err) => {
|
|
208
|
+
if (err) {
|
|
209
|
+
this.log('error', '关闭数据库失败', err);
|
|
210
|
+
} else {
|
|
211
|
+
this.log('info', '数据库已关闭');
|
|
212
|
+
}
|
|
213
|
+
this._db = null;
|
|
214
|
+
this._open = false;
|
|
215
|
+
this._status = 'closed';
|
|
216
|
+
resolve(!err);
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
this._status = 'closed';
|
|
220
|
+
resolve(true);
|
|
221
|
+
}
|
|
222
|
+
} catch (err) {
|
|
223
|
+
this.log('error', '关闭数据库连接时发生异常', err);
|
|
224
|
+
this._status = 'closed';
|
|
225
|
+
resolve(false);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 获取数据库连接
|
|
232
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
233
|
+
* @returns {Promise<object>}
|
|
234
|
+
* @throws {TypeError} 当timeout参数无效时
|
|
235
|
+
*/
|
|
236
|
+
SQLite.prototype.getConn = async function (timeout) {
|
|
237
|
+
// 参数校验
|
|
238
|
+
if (timeout !== undefined && typeof timeout !== 'number') {
|
|
239
|
+
throw new TypeError('timeout must be number');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const acquire_timeout = timeout || this.config.acquire_timeout || this.config.connect_timeout || 20000;
|
|
243
|
+
|
|
244
|
+
if (this._status !== 'connected') {
|
|
245
|
+
await this.open(acquire_timeout);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
if (this._use_pool) {
|
|
250
|
+
// 从连接池获取连接
|
|
251
|
+
return await this._getPoolConnection();
|
|
252
|
+
} else {
|
|
253
|
+
// 单连接模式
|
|
254
|
+
const conn_promise = new Promise((resolve) => {
|
|
255
|
+
resolve(this._db);
|
|
256
|
+
});
|
|
257
|
+
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
258
|
+
setTimeout(() => {
|
|
259
|
+
reject(new Error(`获取数据库连接超时(${acquire_timeout}ms)`));
|
|
260
|
+
}, acquire_timeout);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const conn = await Promise.race([conn_promise, timeout_promise]);
|
|
264
|
+
return conn;
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
this.log('error', '获取连接失败', error);
|
|
268
|
+
|
|
269
|
+
if (error.code && (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT')) {
|
|
270
|
+
this._handleConnectionError(error);
|
|
271
|
+
}
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 执行SQL查询
|
|
278
|
+
* @param {string} sql - SQL语句
|
|
279
|
+
* @param {Array} params - 参数数组
|
|
280
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
281
|
+
* @returns {Promise<object>}
|
|
282
|
+
* @throws {TypeError} 当sql参数无效时
|
|
283
|
+
*/
|
|
284
|
+
SQLite.prototype.run = async function (sql, params = [], timeout = 30000) {
|
|
285
|
+
// 参数校验
|
|
286
|
+
if (typeof sql !== 'string' || sql.trim() === '') {
|
|
287
|
+
throw new TypeError('sql must be non-empty string');
|
|
288
|
+
}
|
|
289
|
+
if (params !== undefined && !Array.isArray(params)) {
|
|
290
|
+
throw new TypeError('params must be array');
|
|
291
|
+
}
|
|
292
|
+
if (timeout !== undefined && typeof timeout !== 'number') {
|
|
293
|
+
throw new TypeError('timeout must be number');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
this.error = null;
|
|
297
|
+
let conn = null;
|
|
298
|
+
const query_timeout = timeout || this.config.query_timeout || 30000;
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
// 获取连接
|
|
302
|
+
conn = await this.getConn(query_timeout);
|
|
303
|
+
|
|
304
|
+
const self = this;
|
|
305
|
+
// 直接在方法内部实现超时控制
|
|
306
|
+
const query_promise = new Promise((resolve, reject) => {
|
|
307
|
+
conn.all(sql, params || [], (error, rows) => {
|
|
308
|
+
if (error) {
|
|
309
|
+
self.sql = sql;
|
|
310
|
+
self.error = {
|
|
311
|
+
code: error.errno,
|
|
312
|
+
message: error.message
|
|
313
|
+
};
|
|
314
|
+
// 不抛出错误,保持与MySQL一致的错误处理行为
|
|
315
|
+
resolve([]);
|
|
316
|
+
} else {
|
|
317
|
+
// 保持与MySQL兼容的返回值格式,始终返回数组
|
|
318
|
+
resolve(rows);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
324
|
+
setTimeout(() => {
|
|
325
|
+
reject(new Error(`SQL查询超时: ${timeout}ms`));
|
|
326
|
+
}, timeout);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const result = await Promise.race([query_promise, timeout_promise]);
|
|
330
|
+
|
|
331
|
+
// 连接池模式下释放连接
|
|
332
|
+
if (this._use_pool && conn) {
|
|
333
|
+
this._releasePoolConnection(conn);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return result;
|
|
337
|
+
} catch (err) {
|
|
338
|
+
this.log('error', 'SQL执行失败', err);
|
|
339
|
+
|
|
340
|
+
// 连接池模式下释放连接
|
|
341
|
+
if (this._use_pool && conn) {
|
|
342
|
+
this._releasePoolConnection(conn);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 处理连接错误,触发重连
|
|
346
|
+
if (err.code && (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT')) {
|
|
347
|
+
this._handleConnectionError(err);
|
|
348
|
+
}
|
|
349
|
+
// 返回空数组,保持与MySQL一致的错误处理行为
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* 执行SQL语句(用于执行非查询语句如INSERT/UPDATE/DELETE)
|
|
356
|
+
* @param {string} sql - SQL语句
|
|
357
|
+
* @param {Array} params - 参数数组
|
|
358
|
+
* @param {number} timeout - 超时时间(毫秒)
|
|
359
|
+
* @returns {Promise<object>}
|
|
360
|
+
* @throws {TypeError} 当sql参数无效时
|
|
361
|
+
*/
|
|
362
|
+
SQLite.prototype.exec = async function (sql, params, timeout) {
|
|
363
|
+
// 参数校验
|
|
364
|
+
if (typeof sql !== 'string' || sql.trim() === '') {
|
|
365
|
+
throw new TypeError('sql must be non-empty string');
|
|
366
|
+
}
|
|
367
|
+
if (params !== undefined && !Array.isArray(params)) {
|
|
368
|
+
throw new TypeError('params must be array');
|
|
369
|
+
}
|
|
370
|
+
if (timeout !== undefined && typeof timeout !== 'number') {
|
|
371
|
+
throw new TypeError('timeout must be number');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
this.error = null;
|
|
375
|
+
let conn = null;
|
|
376
|
+
timeout = timeout || this.config.query_timeout || 30000;
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
// 获取连接
|
|
380
|
+
conn = await this.getConn(timeout);
|
|
381
|
+
var _this = this;
|
|
382
|
+
// 直接在方法内部实现超时控制
|
|
383
|
+
const query_promise = new Promise((resolve, reject) => {
|
|
384
|
+
conn.run(sql, params || [], function (error) {
|
|
385
|
+
if (error) {
|
|
386
|
+
_this.sql = sql;
|
|
387
|
+
_this.error = {
|
|
388
|
+
code: error.errno,
|
|
389
|
+
message: error.message
|
|
390
|
+
};
|
|
391
|
+
// 不抛出错误,保持与MySQL一致的错误处理行为
|
|
392
|
+
resolve(0);
|
|
393
|
+
} else {
|
|
394
|
+
// 保持与MySQL兼容的返回值格式
|
|
395
|
+
resolve(this.lastID || this.changes || 1);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const timeout_promise = new Promise((unused_resolve, reject) => {
|
|
401
|
+
setTimeout(() => {
|
|
402
|
+
reject(new Error(`SQL执行超时: ${timeout}ms`));
|
|
403
|
+
}, timeout);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
const result = await Promise.race([query_promise, timeout_promise]);
|
|
407
|
+
|
|
408
|
+
// 连接池模式下释放连接
|
|
409
|
+
if (this._use_pool && conn) {
|
|
410
|
+
this._releasePoolConnection(conn);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return result;
|
|
414
|
+
} catch (err) {
|
|
415
|
+
this.log('error', 'SQL执行失败', err);
|
|
416
|
+
|
|
417
|
+
// 连接池模式下释放连接
|
|
418
|
+
if (this._use_pool && conn) {
|
|
419
|
+
this._releasePoolConnection(conn);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 处理连接错误,触发重连
|
|
423
|
+
if (err.code && (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT')) {
|
|
424
|
+
this._handleConnectionError(err);
|
|
425
|
+
}
|
|
426
|
+
// 返回0,保持与MySQL一致的错误处理行为
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 读取整张表的数据
|
|
433
|
+
* @param {string} table - 表名
|
|
434
|
+
* @param {object} condition - 查询条件
|
|
435
|
+
* @param {object} options - 选项(order_by, limit, offset等)
|
|
436
|
+
* @returns {Promise<Array>}
|
|
437
|
+
* @throws {TypeError} 当table参数无效时
|
|
438
|
+
*/
|
|
439
|
+
SQLite.prototype.read = async function (table, condition, options) {
|
|
440
|
+
// 参数校验
|
|
441
|
+
if (typeof table !== 'string' || table.trim() === '') {
|
|
442
|
+
throw new TypeError('table must be non-empty string');
|
|
443
|
+
}
|
|
444
|
+
if (condition !== undefined && (typeof condition !== 'object' || Array.isArray(condition))) {
|
|
445
|
+
throw new TypeError('condition must be object');
|
|
446
|
+
}
|
|
447
|
+
if (options !== undefined && (typeof options !== 'object' || Array.isArray(options))) {
|
|
448
|
+
throw new TypeError('options must be object');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
// 检查连接状态
|
|
453
|
+
if (this._status !== 'connected') {
|
|
454
|
+
throw new Error('数据库连接未建立');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// 构建基础SQL查询
|
|
458
|
+
let sql = `SELECT * FROM ${table}`;
|
|
459
|
+
const params = [];
|
|
460
|
+
|
|
461
|
+
// 处理条件
|
|
462
|
+
if (condition && Object.keys(condition).length > 0) {
|
|
463
|
+
const where_clauses = [];
|
|
464
|
+
for (const [field, value] of Object.entries(condition)) {
|
|
465
|
+
where_clauses.push(`${field} = ?`);
|
|
466
|
+
params.push(value);
|
|
467
|
+
}
|
|
468
|
+
sql += ` WHERE ${where_clauses.join(' AND ')}`;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 处理排序
|
|
472
|
+
if (options && options.order_by) {
|
|
473
|
+
sql += ` ORDER BY ${options.order_by}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 处理分页
|
|
477
|
+
if (options && options.limit) {
|
|
478
|
+
sql += ` LIMIT ${options.limit}`;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (options && options.offset) {
|
|
482
|
+
sql += ` OFFSET ${options.offset}`;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// 记录查询日志
|
|
486
|
+
if (this.config.debug) {
|
|
487
|
+
this.log('debug', '查询数据', { sql, params });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// 执行查询
|
|
491
|
+
const results = await this.run(sql, params);
|
|
492
|
+
|
|
493
|
+
if (this.config.debug) {
|
|
494
|
+
this.log('info', '查询成功', { count: Array.isArray(results) ? results.length : 1 });
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 确保返回数组格式
|
|
498
|
+
return Array.isArray(results) ? results : [results];
|
|
499
|
+
} catch (error) {
|
|
500
|
+
this.log('error', '查询失败', error);
|
|
501
|
+
// 返回空数组作为默认值,保持返回值类型一致
|
|
502
|
+
return [];
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* 获取数据库管理器(保持兼容性)
|
|
508
|
+
* @returns {object} DB实例
|
|
509
|
+
*/
|
|
510
|
+
SQLite.prototype.db = function () {
|
|
511
|
+
return new DB(this);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// /**
|
|
515
|
+
// * 获取数据库操作实例
|
|
516
|
+
// * @param {String} database - 数据库名称
|
|
517
|
+
// * @returns {Object} 数据库操作实例
|
|
518
|
+
// * @throws {TypeError} 当database参数无效时
|
|
519
|
+
// */
|
|
520
|
+
// SQLite.prototype.db = function (database) {
|
|
521
|
+
// // 参数校验
|
|
522
|
+
// if (database !== undefined && typeof database !== 'string') {
|
|
523
|
+
// throw new TypeError('database must be string');
|
|
524
|
+
// }
|
|
525
|
+
|
|
526
|
+
// if (this._status !== 'connected') {
|
|
527
|
+
// throw new Error('数据库连接未建立');
|
|
528
|
+
// }
|
|
529
|
+
|
|
530
|
+
// // 优化:缓存DB实例,避免重复创建
|
|
531
|
+
// if (!this._db_instance) {
|
|
532
|
+
// this._db_instance = new DB(this);
|
|
533
|
+
|
|
534
|
+
// // 为DB实例添加必要的方法,确保与MySQL接口兼容
|
|
535
|
+
// this._db_instance.run = this.run.bind(this);
|
|
536
|
+
// this._db_instance.exec = this.exec.bind(this);
|
|
537
|
+
// }
|
|
538
|
+
|
|
539
|
+
// if (database) {
|
|
540
|
+
// this._db_instance.database = database;
|
|
541
|
+
// }
|
|
542
|
+
|
|
543
|
+
// return this._db_instance;
|
|
544
|
+
// };
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* 开始事务
|
|
548
|
+
* @returns {Promise<object>} 事务连接对象
|
|
549
|
+
*/
|
|
550
|
+
SQLite.prototype.beginTrans = async function () {
|
|
551
|
+
try {
|
|
552
|
+
// 检查连接状态
|
|
553
|
+
if (this._status !== 'connected') {
|
|
554
|
+
throw new Error('数据库连接未建立');
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// 获取连接
|
|
558
|
+
const conn = await this.getConn();
|
|
559
|
+
|
|
560
|
+
// 开始事务
|
|
561
|
+
await new Promise((resolve, reject) => {
|
|
562
|
+
conn.run('BEGIN TRANSACTION', (error) => {
|
|
563
|
+
if (error) {
|
|
564
|
+
reject(error);
|
|
565
|
+
} else {
|
|
566
|
+
resolve();
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
if (this.config.debug) {
|
|
572
|
+
this.log('debug', '事务开始');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// 返回事务连接对象,包含提交和回滚方法
|
|
576
|
+
return {
|
|
577
|
+
conn,
|
|
578
|
+
commit: async () => {
|
|
579
|
+
await new Promise((resolve, reject) => {
|
|
580
|
+
conn.run('COMMIT', (error) => {
|
|
581
|
+
if (error) {
|
|
582
|
+
reject(error);
|
|
583
|
+
} else {
|
|
584
|
+
resolve();
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
if (this.config.debug) {
|
|
589
|
+
this.log('debug', '事务提交');
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// 连接池模式下释放连接
|
|
593
|
+
if (this._use_pool) {
|
|
594
|
+
this._releasePoolConnection(conn);
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
rollback: async () => {
|
|
598
|
+
await new Promise((resolve, reject) => {
|
|
599
|
+
conn.run('ROLLBACK', (error) => {
|
|
600
|
+
if (error) {
|
|
601
|
+
reject(error);
|
|
602
|
+
} else {
|
|
603
|
+
resolve();
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
if (this.config.debug) {
|
|
608
|
+
this.log('debug', '事务回滚');
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 连接池模式下释放连接
|
|
612
|
+
if (this._use_pool) {
|
|
613
|
+
this._releasePoolConnection(conn);
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
exec: async (sql, params) => {
|
|
617
|
+
// 在事务中执行SQL
|
|
618
|
+
return new Promise((resolve, reject) => {
|
|
619
|
+
conn.run(sql, params || [], function (error) {
|
|
620
|
+
if (error) {
|
|
621
|
+
this.sql = error.sql;
|
|
622
|
+
this.error = {
|
|
623
|
+
code: error.errno,
|
|
624
|
+
message: error.message
|
|
625
|
+
};
|
|
626
|
+
reject(error);
|
|
627
|
+
resolve(0);
|
|
628
|
+
} else {
|
|
629
|
+
resolve(this.lastID || this.changes || 1);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
} catch (error) {
|
|
636
|
+
this.log('error', '事务开始失败', error);
|
|
637
|
+
// 重新抛出异常,因为调用方需要事务对象
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* 在事务中执行多个操作
|
|
644
|
+
* @param {Function} callback - 包含事务操作的回调函数
|
|
645
|
+
* @returns {Promise<*>} 回调函数的返回值
|
|
646
|
+
* @throws {TypeError} 当callback参数无效时
|
|
647
|
+
*/
|
|
648
|
+
SQLite.prototype.trans = async function (callback) {
|
|
649
|
+
// 参数校验
|
|
650
|
+
if (typeof callback !== 'function') {
|
|
651
|
+
throw new TypeError('callback must be function');
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
let trans = null;
|
|
655
|
+
|
|
656
|
+
try {
|
|
657
|
+
// 开始事务
|
|
658
|
+
trans = await this.beginTrans();
|
|
659
|
+
|
|
660
|
+
// 执行回调函数,传入事务对象
|
|
661
|
+
const result = await callback(trans);
|
|
662
|
+
|
|
663
|
+
// 提交事务
|
|
664
|
+
await trans.commit();
|
|
665
|
+
|
|
666
|
+
return result;
|
|
667
|
+
} catch (error) {
|
|
668
|
+
// 如果有事务,回滚
|
|
669
|
+
if (trans) {
|
|
670
|
+
await trans.rollback().catch(err => {
|
|
671
|
+
this.log('error', '事务回滚失败', err);
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
this.log('error', '事务执行失败', error);
|
|
676
|
+
// 重新抛出异常,因为调用方需要事务执行结果
|
|
677
|
+
throw error;
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* 设置当前操作的表名
|
|
683
|
+
* @param {string} name - 表名
|
|
684
|
+
* @param {string} key - 主键
|
|
685
|
+
* @returns {object} 数据库操作实例
|
|
686
|
+
* @throws {TypeError} 当name参数无效时
|
|
687
|
+
*/
|
|
688
|
+
SQLite.prototype.table = function (name, key) {
|
|
689
|
+
// 参数校验
|
|
690
|
+
if (typeof name !== 'string' || name.trim() === '') {
|
|
691
|
+
throw new TypeError('name must be non-empty string');
|
|
692
|
+
}
|
|
693
|
+
if (key !== undefined && typeof key !== 'string') {
|
|
694
|
+
throw new TypeError('key must be string');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
var db = this.db();
|
|
698
|
+
db.table = name;
|
|
699
|
+
if (key) {
|
|
700
|
+
db.key = key;
|
|
701
|
+
}
|
|
702
|
+
return db;
|
|
703
|
+
};
|
|
704
|
+
|
|
176
705
|
/**
|
|
177
|
-
*
|
|
178
|
-
* @
|
|
179
|
-
* @
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
706
|
+
* 创建SQLite连接
|
|
707
|
+
* @private
|
|
708
|
+
* @returns {Promise<object>} 数据库连接对象
|
|
709
|
+
*/
|
|
710
|
+
SQLite.prototype._createConnection = function () {
|
|
711
|
+
return new Promise((resolve, reject) => {
|
|
712
|
+
const db = new sqlite3.Database(this._getDbFilename(), (err) => {
|
|
713
|
+
if (err) {
|
|
714
|
+
reject(err);
|
|
715
|
+
} else {
|
|
716
|
+
resolve(db);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* 初始化连接池
|
|
724
|
+
* @private
|
|
725
|
+
* @returns {Promise<void>}
|
|
726
|
+
*/
|
|
727
|
+
SQLite.prototype._initPool = async function () {
|
|
728
|
+
if (this._pool_reaper) {
|
|
729
|
+
return; // 连接池已初始化
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
try {
|
|
733
|
+
// 创建最小连接数
|
|
734
|
+
for (let i = 0; i < this.config.pool_min; i++) {
|
|
735
|
+
const conn = await this._createConnection();
|
|
736
|
+
this._pool_connections.push(conn);
|
|
737
|
+
this._pool_available.push(conn);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// 启动连接回收器
|
|
741
|
+
this._pool_reaper = setInterval(() => {
|
|
742
|
+
this._reapIdleConnections();
|
|
743
|
+
}, this.config.pool_reap_interval);
|
|
744
|
+
|
|
745
|
+
this.log('debug', '连接池初始化完成', {
|
|
746
|
+
min: this.config.pool_min,
|
|
747
|
+
max: this.config.pool_max,
|
|
748
|
+
current: this._pool_connections.length
|
|
749
|
+
});
|
|
750
|
+
} catch (error) {
|
|
751
|
+
this.log('error', '连接池初始化失败', error);
|
|
752
|
+
throw error;
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* 回收空闲连接
|
|
758
|
+
* @private
|
|
759
|
+
*/
|
|
760
|
+
SQLite.prototype._reapIdleConnections = function () {
|
|
761
|
+
const now = Date.now();
|
|
762
|
+
const idle_timeout = this.config.pool_idle_timeout;
|
|
763
|
+
|
|
764
|
+
for (let i = this._pool_available.length - 1; i >= 0; i--) {
|
|
765
|
+
const conn = this._pool_available[i];
|
|
766
|
+
if (conn._last_used && now - conn._last_used > idle_timeout) {
|
|
767
|
+
// 关闭并移除空闲连接
|
|
768
|
+
conn.close((err) => {
|
|
769
|
+
if (err) {
|
|
770
|
+
this.log('error', '关闭空闲连接失败', err);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// 从连接池中移除
|
|
775
|
+
const conn_idx = this._pool_connections.indexOf(conn);
|
|
776
|
+
if (conn_idx > -1) {
|
|
777
|
+
this._pool_connections.splice(conn_idx, 1);
|
|
778
|
+
}
|
|
779
|
+
this._pool_available.splice(i, 1);
|
|
780
|
+
|
|
781
|
+
this.log('debug', '回收空闲连接');
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* 从连接池获取连接
|
|
788
|
+
* @private
|
|
789
|
+
* @returns {Promise<object>} 数据库连接
|
|
790
|
+
*/
|
|
791
|
+
SQLite.prototype._getPoolConnection = async function () {
|
|
792
|
+
const acquire_timeout = this.config.pool_acquire_timeout;
|
|
793
|
+
const start_time = Date.now();
|
|
794
|
+
|
|
795
|
+
return new Promise((resolve, reject) => {
|
|
796
|
+
const tryGetConnection = () => {
|
|
797
|
+
// 检查超时
|
|
798
|
+
if (Date.now() - start_time > acquire_timeout) {
|
|
799
|
+
reject(new Error(`获取连接超时(${acquire_timeout}ms)`));
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// 检查是否有可用连接
|
|
804
|
+
if (this._pool_available.length > 0) {
|
|
805
|
+
const conn = this._pool_available.shift();
|
|
806
|
+
conn._last_used = Date.now();
|
|
807
|
+
resolve(conn);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// 检查是否可以创建新连接
|
|
812
|
+
if (this._pool_connections.length < this.config.pool_max) {
|
|
813
|
+
this._createConnection()
|
|
814
|
+
.then(conn => {
|
|
815
|
+
this._pool_connections.push(conn);
|
|
816
|
+
conn._last_used = Date.now();
|
|
817
|
+
resolve(conn);
|
|
818
|
+
})
|
|
819
|
+
.catch(reject);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// 没有可用连接,等待一段时间后重试
|
|
824
|
+
setTimeout(tryGetConnection, 100);
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
tryGetConnection();
|
|
828
|
+
});
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* 释放连接回连接池
|
|
833
|
+
* @private
|
|
834
|
+
* @param {object} conn - 数据库连接
|
|
835
|
+
*/
|
|
836
|
+
SQLite.prototype._releaseConn = function (conn) {
|
|
837
|
+
if (this._pool_connections.includes(conn)) {
|
|
838
|
+
conn._last_used = Date.now();
|
|
839
|
+
this._pool_available.push(conn);
|
|
840
|
+
|
|
841
|
+
// 处理等待队列
|
|
842
|
+
if (this._pool_waiting.length > 0) {
|
|
843
|
+
const waiting = this._pool_waiting.shift();
|
|
844
|
+
waiting.resolve(conn);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* 释放连接池连接
|
|
851
|
+
* @private
|
|
852
|
+
* @param {object} conn - 数据库连接
|
|
853
|
+
*/
|
|
854
|
+
SQLite.prototype._releasePoolConnection = function (conn) {
|
|
855
|
+
if (!conn || !this._pool_connections.includes(conn)) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// 标记连接最后使用时间
|
|
860
|
+
conn._last_used = Date.now();
|
|
861
|
+
|
|
862
|
+
// 将连接放回可用连接池
|
|
863
|
+
if (!this._pool_available.includes(conn)) {
|
|
864
|
+
this._pool_available.push(conn);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// 如果有等待的连接请求,立即处理
|
|
868
|
+
if (this._pool_waiting.length > 0) {
|
|
869
|
+
const waiting = this._pool_waiting.shift();
|
|
870
|
+
const next_conn = this._pool_available.shift();
|
|
871
|
+
if (next_conn && waiting.resolve) {
|
|
872
|
+
waiting.resolve(next_conn);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* 关闭连接池
|
|
879
|
+
* @private
|
|
880
|
+
*/
|
|
881
|
+
SQLite.prototype._closePool = function () {
|
|
882
|
+
if (this._pool_reaper) {
|
|
883
|
+
clearInterval(this._pool_reaper);
|
|
884
|
+
this._pool_reaper = null;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// 关闭所有连接
|
|
888
|
+
this._pool_connections.forEach(conn => {
|
|
889
|
+
try {
|
|
890
|
+
conn.close((err) => {
|
|
891
|
+
if (err) {
|
|
892
|
+
this.log('error', '关闭连接池连接失败', err);
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
} catch (error) {
|
|
896
|
+
this.log('error', '关闭连接池连接异常', error);
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
this._pool_connections = [];
|
|
901
|
+
this._pool_available = [];
|
|
902
|
+
this._pool_waiting = [];
|
|
903
|
+
|
|
904
|
+
this.log('debug', '连接池已关闭');
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* 确保连接池对象存在
|
|
909
|
+
*/
|
|
910
|
+
if (!$.pool) {
|
|
911
|
+
$.pool = {};
|
|
192
912
|
}
|
|
913
|
+
if (!$.pool.sqlite) {
|
|
914
|
+
$.pool.sqlite = {};
|
|
915
|
+
}
|
|
916
|
+
|
|
193
917
|
/**
|
|
194
|
-
*
|
|
918
|
+
* Sqlite管理器,用于创建缓存
|
|
919
|
+
* @param {string} scope 作用域
|
|
920
|
+
* @param {object} config 配置参数
|
|
921
|
+
* @returns {object} 返回一个Sqlite类实例
|
|
195
922
|
*/
|
|
196
|
-
|
|
923
|
+
function sqliteAdmin(scope, config) {
|
|
924
|
+
if (!scope) {
|
|
925
|
+
scope = 'sys';
|
|
926
|
+
}
|
|
927
|
+
var obj = $.pool.sqlite[scope];
|
|
928
|
+
if (!obj) {
|
|
929
|
+
$.pool.sqlite[scope] = new SQLite(config);
|
|
930
|
+
obj = $.pool.sqlite[scope];
|
|
931
|
+
}
|
|
932
|
+
return obj;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// 模块导出
|
|
936
|
+
exports.SQLite = SQLite;
|
|
937
|
+
exports.sqliteAdmin = sqliteAdmin;
|