यह पृष्ठ पुर्तगाली से मशीन-अनुवादित है और इसमें त्रुटियाँ हो सकती हैं। पुर्तगाली संस्करण प्रामाणिक है।
SQLite के साथ पर्सिस्टेंस
CrossFly में संरचित डेटा को पर्सिस्ट करने का कैननिकल तरीका dev.crossfly.sqlite मॉड्यूल है —
नेटिव लाइब्रेरी cfsqlite (SQLite3MultipleCiphers) के ऊपर एक पतली परत। यह पुराने
dev.crossfly.sql (JDBC) की जगह लेता है।
डेटाबेस को पेंट थ्रेड के बाहर चलाएँ और
Component.onUI(...)के साथ UI पर लौटें (देखें बैकग्राउंड में काम)।SqliteDb,SqliteStmtऔरSqliteCursorसभीAutoCloseableहैं → try-with-resources का उपयोग करें।
खोलना / बंद करना
try (SqliteDb db = SqliteDb.open("app.db")) {
db.exec("CREATE TABLE IF NOT EXISTS cliente(id INTEGER PRIMARY KEY, nome TEXT, idade INTEGER)");
// … db उपयोग करें …
} // खुद ही बंद हो जाता है
फ़ैक्ट्रीज़: SqliteDb.open(String), open(String, int flags), open(String, byte[] key) (एन्क्रिप्टेड),
openMemory()।
पैरामीटराइज़्ड CRUD
// INSERT/UPDATE/DELETE → execute(sql, params...) प्रभावित पंक्तियों की संख्या लौटाता है
db.execute("INSERT INTO cliente(nome, idade) VALUES(?, ?)", "Ana", 30);
db.execute("UPDATE cliente SET idade=? WHERE id=?", 31, 1);
// SELECT → query(sql, params...) एक cursor देता है
try (SqliteCursor c = db.query("SELECT id, nome, idade FROM cliente WHERE idade > ?", 18)) {
while (c.next()) {
long id = c.getLong(0); // ⚠️ cursor के getter 0-based होते हैं
String nome= c.getString(1);
int idade = c.getInt(2);
}
}
// एकल मान:
long total = db.queryLong("SELECT COUNT(*) FROM cliente", 0);
String nome = db.queryString("SELECT nome FROM cliente WHERE id=?", 1);
⚠️ इंडेक्स की पेचीदगी: bind 1-based, getters 0-based
| ऑपरेशन | बेस | उदाहरण |
|---|---|---|
पैरामीटर का bind (SqliteStmt) |
1-based | stmt.bindString(1, nome) |
कॉलम का getter (SqliteCursor) |
0-based | cursor.getString(0) |
यह मॉड्यूल की सबसे आम गलती है — ? 1 से शुरू होते हैं, परिणाम के कॉलम 0 से।
ट्रांज़ैक्शन और बल्क राइट
db.transaction(() -> { // स्वचालित begin/commit (अपवाद पर rollback)
db.execute("INSERT INTO cliente(nome) VALUES(?)", "A");
db.execute("INSERT INTO cliente(nome) VALUES(?)", "B");
});
// मैनुअल begin/commit/rollback भी मौजूद हैं:
db.begin(); /* … */ db.commit();
// बल्क राइट (statement आंतरिक रूप से पुनः उपयोग होता है):
List<Object[]> linhas = List.of(new Object[]{"A", 1}, new Object[]{"B", 2});
db.bulkInsert("INSERT INTO cliente(nome, idade) VALUES(?, ?)", linhas);
पुनः उपयोग करने योग्य प्रिपेयर्ड स्टेटमेंट
try (SqliteStmt st = db.prepare("INSERT INTO cliente(nome, idade) VALUES(?, ?)")) {
for (Cliente c : lista) {
st.bindAll(c.nome, c.idade); // या bindString(1, ...).bindInt(2, ...)
st.step();
st.reset(); // statement का पुनः उपयोग करता है
}
}
वैकल्पिक एन्क्रिप्शन
byte[] chave = obterChave(); // आपकी key (byte[])
try (SqliteDb db = SqliteDb.open("secreto.db", chave)) { // डिफ़ॉल्ट रूप से ChaCha20-Poly1305 सिफर
// … एन्क्रिप्टेड डेटाबेस …
db.rekey(novaChave); // key बदलें (या दूसरी पास करके हटाएं)
}
बिना चाबी के = सामान्य SQLite, शून्य ओवरहेड। समर्थित सिफर में CHACHA20 (डिफ़ॉल्ट),
SQLCIPHER, AES256CBC आदि शामिल हैं (Sqlite.Cipher)।
की/वैल्यू टेबल (पुराने हल्के पर्सिस्टेंस की जगह)
हल्का पर्सिस्टेंस (Settings.appSettings) हटा दिया गया है। फ़्लैग/थीम/अंतिम लॉगिन के लिए, एक
की/वैल्यू टेबल यह हल कर देती है:
db.exec("CREATE TABLE IF NOT EXISTS kv(k TEXT PRIMARY KEY, v TEXT)");
db.execute("INSERT OR REPLACE INTO kv(k, v) VALUES(?, ?)", "tema", "escuro");
String tema = db.queryString("SELECT v FROM kv WHERE k=?", "tema");
देखें फ़ाइलें और प्राथमिकताएँ।
अच्छी प्रथाएँ
- हमेशा try-with-resources (db, stmt, cursor) — नेटिव हैंडल लीक होने से बचाता है।
- बैच राइट →
transaction(...)/bulkInsert(...)(कई गुना तेज़)। - डेटाबेस पेंट थ्रेड के बाहर; परिणाम
onUI(...)के साथ वापस।
आम गलतियाँ
- बेस उलट देना:
?1-based है, कर्सर का कॉलम 0-based है। - पेंट थ्रेड पर क्वेरी चलाना और UI को फ़्रीज़ कर देना।
- कर्सर/स्टेटमेंट बंद करना भूल जाना (नेटिव संसाधन लीक होता है)।