SQLite este o bază de date relațională încorporată care funcționează fără un proces server separat și stochează întreaga bază de date într-un singur fișier pe dispozitiv. Datorită configurării zero, dimensiunii reduse a bibliotecii și suportului complet pentru SQL, SQLite a devenit standardul pentru stocarea locală a datelor în aplicațiile mobile. Conform datelor SQLite Consortium (2025), acest SGBD este utilizat în peste 4 miliarde de dispozitive, inclusiv fiecare smartphone pe iOS și Android.
Principalele idei
SQLite este o bibliotecă în limbajul C care implementează un SGBD relațional fără server dedicat. Este încorporată direct în aplicație, citește și scrie date într-un fișier obișnuit pe sistemul de fișiere al dispozitivului. Dimensiunea bibliotecii este de aproximativ 600 KB, ceea ce face din SQLite cea mai ușoară bază de date SQL complet funcțională.
SQLite suportă cea mai mare parte a standardului SQL:1999, inclusiv JOIN, subinterogări, declanșatoare, vizualizări, indecși și funcții fereastră. Limitările se referă la ALTER TABLE (suport limitat) și la RIGHT/FULL OUTER JOIN complete. Cu toate acestea, pentru aplicațiile mobile, funcționalitatea SQLite este suficientă în 99% din cazurile de stocare locală.
Conform sondajului dezvoltatorilor de pe Stack Overflow (2025), SQLite este cea mai populară bază de date pentru soluții încorporate și ocupă locul trei ca popularitate între toate SGBD-urile, după MySQL și PostgreSQL. În dezvoltarea mobilă, SQLite este folosită în fiecare aplicație — direct sau prin intermediul unor stratificări.
Zero-configuration — SQLite nu necesită instalare, configurare a permisiunilor, creare de utilizatori sau pornirea unui serviciu. Biblioteca se conectează la proiect, iar baza de date se creează prin apelarea unei singure funcții. Acest lucru simplifică radical implementarea în comparație cu SGBD-urile client-server, care necesită instalarea serverului, configurarea porturilor și configurarea utilizatorilor.
Fișierul bazei de date SQLite este un fișier obișnuit cross-platform care poate fi copiat, analizat, trimis prin rețeaua sau restaurat dintr-o copie de rezervă. Formatul fișierului este stabil la nivel de API: fișierele SQLite 3 create în 2004 se deschid cu versiunea curentă a bibliotecii, ceea ce garantează compatibilitatea pe termen lung a datelor.
Arhitectura SQLite constă din opt mașini virtuale: Tokenizer, Parser, Code Generator, VM, B-Tree, Pager, OS Interface și Utilities. O interogare SQL trece prin Tokenizer (împărțire în tokeni), Parser (construirea AST), Code Generator (conversia în cod de octeți) și este executată pe mașina virtuală care citește paginile de date prin B-Tree și Pager.
SQLite utilizează B-Tree pentru stocarea tabelelor și indecșilor. Fiecare tabelă este stocată ca un B-Tree separat, unde nodurile frunză conțin rândurile de date. Indecșii sunt de asemenea stocați ca B-Tree, dar cu chei în frunze. Pager gestionează încărcarea paginilor (implicit 4096 de octeți) din fișier în memorie, asigurând tranzacții ACID prin jurnal sau WAL.
WAL (Write-Ahead Logging) — modul recomandat pentru aplicațiile mobile. Modificările sunt scrise mai întâi într-un fișier WAL separat, apoi transferate periodic în baza de date principală. WAL permite citirea simultană din baza de date (date vechi) și scrierea în ea (prin WAL), ceea ce îmbunătățește performanța aplicațiilor multi-threaded. Jurnalul standard (rollback journal) blochează citirea în timpul scrierii.
| Parametru | Rollback Journal | WAL (Write-Ahead Logging) |
|---|---|---|
| Citirea în timpul scrierii | Blocată | Permisă (citește date vechi) |
| Performanța scrierii | Medie | Ridicată (scriere secvențială în WAL) |
| Consumul de disc | Mai mic (doar jurnalul de revenire) | Mai mare (WAL + baza principală) |
| Recuperarea după avarie | Revenire la ultimul punct de control | Recuperare din WAL (datele nu se pierd) |
| Recomandare | Pentru scenarii single-thread | Pentru aplicații mobile tipice |
Comutarea între moduri se face cu o singură interogare SQL: PRAGMA journal_mode=WAL. Pentru aplicațiile mobile cu sincronizare în fundal și un fir UI care citește simultan datele, WAL oferă o performanță mai bună și fără blocarea interfeței.
SQLite nu este singura opțiune pentru stocarea locală a datelor, dar este cea mai universală. Realm oferă o viteză mai mare de acces direct la obiectele din memorie, dar folosește propriul format NoSQL și are o dimensiune mai mare a bibliotecii. Core Data pe iOS este un strat ORM peste SQLite care adaugă gestionarea grafului de obiecte și anularea operațiilor.
Pentru majoritatea aplicațiilor, SQLite rămâne alegerea optimă datorită performanței previzibile, lipsei de dependență de vendor și stabilității testate în timp. Realm și Core Data sunt justificate în proiecte cu grafuri complexe de obiecte, interogări reactive sau cerințe de sincronizare între dispozitive.
| Caracteristică | SQLite | Realm | Core Data |
|---|---|---|---|
| Tipul bazei de date | Relațională (SQL) | NoSQL (orientată pe obiecte) | ORM (peste SQLite) |
| Dimensiunea bibliotecii | ~600 KB | ~4 MB | Încorporată în SDK-ul Apple |
| Performanța | Medie | Ridicată (obiecte în memorie) | Medie (supliment ORM) |
| Platforme | iOS, Android, Web, Desktop | iOS, Android, Node.js | iOS, macOS |
| Dependența de vendor | Nu (standard deschis) | Medie (format propriu) | Ridicată (doar Apple) |
Alegerea între SQLite, Realm și Core Data depinde de platformă, cerințele modelului de obiecte și strategia de sincronizare. Pentru proiecte cross-platform (KMP, Flutter), SQLite rămâne singura alegere universală care funcționează pe toate platformele țintă fără modificări ale modelului de date.
Room — o bibliotecă din Android Jetpack care oferă un strat ORM peste SQLite. Room generează automat interogările SQL din interfețele DAO adnotate, verifică corectitudinea interogărilor în faza de compilare și suportă migrațiile bazei de date la modificarea schemei. Room este modul recomandat de lucru cu SQLite pe Android.
SQLiteOpenHelper — o API de nivel scăzut pentru gestionarea directă a SQLite fără ORM. Clasa gestionează crearea, deschiderea și actualizarea bazei de date. SQLiteOpenHelper este potrivit pentru proiecte cu interogări SQL simple sau când este necesar controlul total asupra logicii SQL fără abstractizarea Room.
Entitatea în Room este adnotată cu @Entity, iar DAO — cu @Dao. Room traduce metodele adnotate în interogări SQL: @Insert generează INSERT, @Query — SELECT cu SQL-ul specificat. Migrațiile se adaugă prin Migration cu indicarea versiunii vechi și noi a schemei. Room verifică SQL-ul în faza de compilare, ceea ce elimină erorile de sintaxă în producție.
@Entity
data class User(
@PrimaryKey val id: Long,
val name: String,
@ColumnInfo(name = "created_at")
val createdAt: Long
)
@Dao
interface UserDao {
@Query("SELECT * FROM user ORDER BY name ASC")
suspend fun getAllUsers(): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Query("DELETE FROM user WHERE id = :id")
suspend fun deleteUser(id: Long)
}
Room generează automat implementarea UserDao_Impl, care conține interogări în timp de execuție către SQLite prin intermediul RoomDatabase intern. Datorită corutinelor (suspend), metodele DAO sunt executate asincron pe firul de fundal, fără a bloca UI. Tipurile de returnare Flow în @Query actualizează automat rezultatul la modificarea tabelului.
FMDB — o încapsulare Objective-C peste API-ul C al SQLite, prima bibliotecă populară din punct de vedere istoric pentru iOS. Oferă obiectele FMDatabase și FMResultSet pentru executarea interogărilor și obținerea rezultatelor. FMDB este simplă și minimalistă, dar nu suportă construcții specifice Swift — opționale, Codable, async/await.
GRDB — o bibliotecă modernă Swift pentru lucrul cu SQLite. Oferă o API type-safe, suport pentru Codable, Combine Publishers, async/await, migrații și monitorizarea modificărilor în timp real. GRDB este preferată pentru proiecte noi în Swift datorită integrării complete cu Swift Concurrency și lizibilității mai bune a codului.
GRDB definește tabelele prin clase Record conforme cu protocoalele FetchableRecord și TableRecord. Interogările sunt scrise în Swift cu sintaxă type-safe, nu în SQL brut. GRDB suportă de asemenea DatabaseMigrator pentru versionarea schemei și migrații între versiunile aplicației.
struct User: Codable, FetchableRecord, TableRecord {
var id: Int64
var name: String
var createdAt: Date
}
let dbPool = try DatabasePool(path: dbPath)
var migrator = DatabaseMigrator()
migrator.registerMigration("v1") { db in
try db.create(table: "user") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
t.column("createdAt", .datetime).notNull()
}
}
let users = try await dbPool.read { db in
try User.order(Column("name")).fetchAll(db)
}
DatabasePool utilizează modul WAL al SQLite pentru citire concurentă. Mai mulți cititori pot accesa simultan baza de date, în timp ce un singur scriitor actualizează datele prin WAL. GRDB gestionează automat conexiunile și tranzacțiile, asigurând accesul thread-safe la bază din orice fir fără sincronizare manuală.
Indecșii — cel mai eficient mod de a accelera interogările SQLite. Un index este creat pe coloanele care participă la WHERE, JOIN și ORDER BY. Pentru un tabel cu 100 000 de înregistrări, căutarea după o coloană indexată durează milisecunde în loc de secunde. Cu toate acestea, indecșii încetinesc INSERT și UPDATE, deci numărul lor trebuie echilibrat cu frecvența scrierii.
Inserarea în lot (batch insert) în cadrul unei singure tranzacții accelerează radical încărcarea în masă a datelor. Inserarea a 1000 de înregistrări una câte una are un supliment de ~1 secundă. Aceleași 1000 de înregistrări într-o singură tranzacție — ~5–10 milisecunde. Diferența se explică prin faptul că fiecare INSERT separat creează o nouă tranzacție cu scriere sincronă pe disc.
PRAGMA — comenzi SQLite pentru configurarea comportamentului bibliotecii. Pragmele cheie de optimizare: PRAGMA synchronous=NORMAL (reduce frecvența fsync), PRAGMA cache_size=-8000 (alocă 8 MB de cache), PRAGMA temp_store=MEMORY (tabele temporare în memorie). Pentru aplicațiile mobile cu volume mari de date, combinația acestor pragme accelerează interogările de 2–3 ori.
O altă optimizare importantă este compilarea prealabilă a interogărilor SQL (prepared statements). Dacă o interogare este executată de mai multe ori (de exemplu, inserarea a 10 000 de rânduri), compilarea SQL o singură dată și apoi utilizarea statement-ului reduce încărcarea CPU cu 30–50%. Room și GRDB stochează automat în cache prepared statements, dar la utilizarea directă a API-ului C al SQLite, compilarea trebuie efectuată manual.
class UserRepository(private val db: RoomDatabase) {
suspend fun insertBatch(users: List<User>) {
db.withTransaction {
users.chunked(500).forEach { batch ->
batch.forEach { user ->
insertUser(user)
}
}
}
}
}
Inserarea în lot cu withTransaction garantează că toate INSERT-urile sunt executate în cadrul unei singure tranzacții. Împărțirea în subloturi (chunked) previne o tranzacție prea mare care ar putea bloca alte fire pentru o perioadă lungă. Pentru sincronizarea în fundal, dimensiunea sublotului de 500 de înregistrări oferă un echilibru optim între viteză și receptivitatea UI.
Întrebări frecvente
Da, SQLite suportă accesul multi-thread în modul WAL. Mai multe fire pot citi simultan datele, dar doar unul poate scrie. Room și GRDB gestionează sincronizarea automat. În modul rollback journal (implicit), baza de date este complet blocată la orice scriere.
Limita SQLite — 281 TB (maximul teoretic). în practică, dimensiunea bazei este limitată de memoria disponibilă a dispozitivului. Pentru aplicațiile mobile, o dimensiune confortabilă este de până la 1–2 GB. Bazele mai mari de 2 GB încetinesc backup-ul, actualizarea prin App Store și cresc consumul de memorie RAM.
SQLite nu criptează datele în mod implicit — orice proces cu acces la fișier le poate citi. Pentru criptare, folosiți SQLCipher (extensie cu AES-256), Room cu EncryptedDatabase (Android) sau Encrypted Core Data pe iOS. Criptarea adaugă 5–15% suprasarcină la citirea și scrierea datelor.
SQLite este o bibliotecă încorporată (embedded) care nu necesită un proces server. MySQL este un SGBD client-server cu server separat, utilizatori, drepturi de acces și protocol de rețea. SQLite stochează baza de date într-un singur fișier, MySQL — în mai multe fișiere gestionate de server. SQLite este mai simplă și mai ușoară, MySQL mai puternică și mai scalabilă.
Pentru migrare, folosiți ALTER TABLE (adăugarea coloanelor) sau crearea unui nou tabel cu transferul datelor și ștergerea celui vechi. Room automatizează acest proces prin clasele Migration: specificați startVersion, endVersion și interogările SQL pentru modificarea schemei. GRDB și FMDB oferă DatabaseMigrator similare.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și