SQL Builder Terbaik - gunakan jOOQ di Android

SQL Builder Terbaik. Menggunakan jOOQ di Android


Pendahuluan


Saat mengembangkan aplikasi Android, cukup wajar untuk menggunakan database SQLite sebagai penyimpanan utama. Biasanya, basis data pada perangkat seluler memiliki skema yang sangat sederhana dan terdiri dari 10-15 tabel. Hampir semua SQL Builder, ORM, atau bahkan API SQLite kosong cocok untuk kasus seperti itu.


Tetapi, sayangnya, tidak semua pengembang beruntung, dan kadang-kadang banyak dari kita untuk menggambarkan model data besar, menggunakan prosedur yang tersimpan, mengkonfigurasi pekerjaan dengan tipe data khusus atau menulis 10 INNER BERGABUNG dalam kueri untuk entitas yang sangat tebal. Jadi hamba setia Anda tidak beruntung, dari mana bahan untuk artikel ini muncul. Nah, masa-masa sulit membutuhkan tindakan keras. Jadi, putar jOOQ di Android.


Semuanya akan baik-baik saja, tetapi


Tetapi ada dua fakta yang perlu diatasi. Yang pertama adalah menunggu di awal bekerja dengan JOOQ: pada tahap ideologis. Untuk memulai proses pembuatan kode, Anda perlu, pada kenyataannya, untuk mendapatkan basis data di mana plugin jooq akan terhubung. Masalah ini mudah dipecahkan, kami membuat proyek templat dengan deskripsi tugas bertahap untuk pembuatan, setelah itu kami membuat basis data secara lokal, menentukan jalur di konfigurasi, meluncurkan plug-in dan menyalin sumber yang diterima ke proyek kami.


Selanjutnya, katakanlah kita menghasilkan semua kelas yang diperlukan. Kami tidak akan dapat menyalinnya ke proyek Android - dependensi tambahan akan diperlukan, yang pertama adalah pada javax annotations. Dua opsi, keduanya lumrah. Tambahkan pustaka (org.glassfish: javax.annotation), atau - gunakan alat yang luar biasa - temukan & ganti dalam ruang lingkup.


Dan tampaknya semuanya baik-baik saja, semua preset sudah selesai, kelas-kelas disalin dan diimpor ke dalam proyek. Mungkin Anda bahkan dapat meluncurkan aplikasi, dan ada kemungkinan itu akan berhasil. Jika Anda diminta untuk mendukung Android API Level <24 - jangan tertipu, ini bukan akhir dari perjalanan kami. Faktanya adalah bahwa JOOQ saat ini dalam versi open-source menggunakan Java 8 dalam banyak hal, yang, seperti Anda ketahui, adalah teman di Android yang sangat kondisional. Masalah ini juga dapat diselesaikan dengan dua cara: membeli jOOQ, menulis untuk mendukung, dan dengan sedih meminta versi di Java 6 atau Java 7 (ada, dilihat dari artikel di jaringan), atau jika Anda, seperti milik saya, tidak memiliki yang tangguh kebutuhan untuk memiliki semua inovasi terbaru perpustakaan, serta keinginan untuk membayar, yaitu, cara kedua. JOOQ mulai bermigrasi ke Java 8 belum lama ini. Versi terakhir sebelum migrasi adalah 3.6.0, yang berarti bahwa kita dapat menggunakan generator dengan parameter groovy version = '3.6.0' dan mendukung versi perangkat yang lebih lama.


Dan hal terakhir yang menunggu penggemar yang telah berjalan di sepanjang jalan keputusasaan ini. Di Android, pada prinsipnya, tidak ada JDBC, yang berarti bahwa sudah saatnya Anda menyilangkan jari untuk mencari solusi pihak ketiga. Untungnya, ada perpustakaan serupa - SQLDroid.


Itu saja. Tahap-tahap utama dan tindakan-tindakan pada mereka dilukis dengan lancar. Sekarang mari kita beralih ke kode, semuanya cukup logis secara umum, tetapi untuk mengurangi waktu Anda, saya akan memberikan contoh dari proyek saya sendiri.


Pembuatan Kode


Pengaturan plugin jOOQ akan terlihat seperti ini:


 buildScript { repositories { mavenCentral() } dependencies { classpath "nu.studer:gradle-jooq-plugin:$jooq_plugin_version" } } apply plugin: 'nu.studer.jooq' dependencies { jooqRuntime "org.xerial:sqlite-jdbc:$xerial_version" } jooq { version = '3.6.0' edition = 'OSS' dev(sourceSets.main) { jdbc { driver = 'org.sqlite.JDBC' url = 'jdbc:sqlite:/Path/To/Database/database.db3' } generator { name = 'org.jooq.util.DefaultGenerator' strategy { name = 'org.jooq.util.DefaultGeneratorStrategy' } database { name = 'org.jooq.util.sqlite.SQLiteDatabase' } generate { relations = true deprecated = false records = true immutablePojos = true fluentSetters = true } target { packageName = 'com.example.mypackage.data.database' } } } } 

Android


Ketergantungan yang Diperlukan:


 implementation "org.jooq:jooq:$jooq_version" implementation "org.sqldroid:sqldroid:$sqldroid_version" implementation "org.glassfish:javax.annotation:$javax_annotations_version" 

Dan sekarang kode sumber dari kelas wrapper untuk bekerja dengan jOOQ melalui SQLiteOpenHelper. Secara umum, seseorang dapat melakukannya tanpa itu, tetapi akan jauh lebih nyaman (menurut saya) untuk menggunakan API yang satu dan yang kedua dengan aman.


 class DatabaseAdapter(private val context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { companion object { private const val DATABASE_NAME = "database" private const val DATABASE_VERSION = 1 @JvmStatic private val OPEN_OPTIONS = mapOf( "cache" to "shared", "journal_mode" to "WAL", "synchronous" to "ON", "foreign_keys" to "ON") } val connectionLock: ReentrantLock = ReentrantLock(true) val configuration: Configuration by lazy(mode = LazyThreadSafetyMode.NONE) { connectionLock.withLock { // ensure the database exists, // all upgrades are performed, // and connection is ready to be set val database = context.openOrCreateDatabase( DATABASE_NAME, Context.MODE_PRIVATE, null) if (database.isOpen) { database.close() } // register SQLDroid driver to be used for establishing connections // with our database DriverManager.registerDriver( Class.forName("org.sqldroid.SQLDroidDriver") .newInstance() as Driver) DefaultConfiguration() .set(SQLiteSource( context, OPEN_OPTIONS, "database", arrayOf("databases"))) .set(SQLDialect.SQLITE) } } override fun onCreate(db: SQLiteDatabase) { // acquire monitor until the database connection is created // this is important as otherwise transactions might be tryingg to run // concurrently that will lead to crashes connectionLock.withLock { // TODO: Create tables } } override fun onOpen(db: SQLiteDatabase) { // acquire monitor until the database connection is established // this is important as otherwise transactions might be tryingg to run // concurrently that will lead to crashes connectionLock.withLock { super.onOpen(db) } } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { // acquire monitor until the database is upgraded // this is important as otherwise transactions might be tryingg to run // concurrently that will lead to crashes connectionLock.withLock { } } infix inline fun <reified T> transaction(noinline f: (Configuration) -> T): Observable<T> = Observable.create { emitter -> val tryResult = Try { connectionLock.withLock { DSL.using(configuration).transactionResult(f) } } when (tryResult) { is Try.Success -> { emitter.onNext(tryResult.value) emitter.onComplete() } is Try.Failure -> { emitter.onError(tryResult.exception) } } } fun invalidate() { connectionLock.withLock { // TODO: Drop tables, vacuum and create tables } } private class SQLiteSource(val context: Context, val options: Map<String, String>, val database: String, val fragments: Array<out String>): DroidDataSource() { override fun getConnection(): Connection = openConnection(options) private fun openConnection(options: Map<String, String> = emptyMap()): Connection { return DriverManager.getConnection(StringBuilder().apply { append("jdbc:sqldroid:") append(context.applicationInfo.dataDir) append("/") append(buildFragments(fragments)) append(database) append("?") append(buildOptions(options)) }.toString()) } private fun buildFragments(fragments: Array<out String>) = when (fragments.isEmpty()) { true -> "" false -> "${fragments.joinToString("/")}/" } private fun buildOptions(options: Map<String, String>) = options.mapTo(mutableListOf<String>()) { entry -> "${entry.key}=${entry.value}" } .joinToString(separator = "&") } } 

UPD: menambahkan mode = LazyThreadSafetyMode.NONE ke inisialisasi malas, terima kasih konstantin_berkow


Alih-alih sebuah kesimpulan


Ternyata, pengaturan jOOQ di Android bukanlah proses yang rumit. Sudah cukup untuk melakukannya sekali, dan kemudian Anda dapat dengan aman melakukan copy-paste dari proyek lama.


Dan bonus kecil yang memberi jOOQ kepada mereka yang menggunakannya. Seperti yang Anda lihat dari contoh, saat membuka koneksi, mode cache digunakan. Apa itu tsime? Android SDK SQLite API tidak menyediakan kemampuan untuk bekerja dengan database dalam mode ini, sangat membatasi kami dalam organisasi komunikasi antarproses dalam aplikasi. Sekarang - Anda dapat dengan aman menggunakan mode ini, yang dengan sendirinya dapat berfungsi sebagai alasan untuk transisi ke kerangka kerja yang indah ini.

Source: https://habr.com/ru/post/id422303/


All Articles