Bebener pisanan, utawa kenapa sistem kudu dirancang adhedhasar struktur database

Hey Habr!

Kita terus njelajah topik kasebut Jawa ΠΈ springkalebu ing tingkat database. Dina iki kita kurban kanggo maca babagan apa, nalika ngrancang aplikasi gedhe, iku struktur database, lan dudu kode Jawa, sing kudu nemtokake pentinge, carane iki rampung, lan apa pangecualian kanggo aturan iki.

Ing artikel sing rada telat iki, aku bakal nerangake kenapa aku mikir yen meh kabeh kasus, model data ing aplikasi kudu dirancang "saka database" tinimbang "saka kapabilitas Jawa" (utawa basa klien apa wae sing sampeyan gunakake. nggarap). Kanthi milih pendekatan kaloro, sampeyan mlebu dalan sing lara lan nandhang sangsara yen proyek sampeyan wiwit tuwuh.

Artikel kasebut ditulis adhedhasar siji pitakonan, diwenehi ing Stack Overflow.

Diskusi sing menarik babagan reddit ing bagean /r/jawa ΠΈ /r/pemrograman.

Generasi kode

Carane kaget aku sing ana lapisan cilik saka pangguna sing, wis dadi kenalan karo jOOQ, resent kasunyatan sing jOOQ akeh gumantung ing generasi kode sumber kanggo mbukak. Ora ana sing ngalangi sampeyan nggunakake jOOQ kaya sing dikarepake, lan ora ana sing meksa sampeyan nggunakake generasi kode. Nanging kanthi gawan (kaya sing diterangake ing manual), jOOQ bisa kaya mangkene: sampeyan miwiti nganggo skema database (warisan), reverse engineer karo generator kode jOOQ kanggo entuk sakumpulan kelas sing makili tabel sampeyan, banjur tulis jinis- pitakon aman marang tabel iki:

	for (Record2<String, String> record : DSL.using(configuration)
//   ^^^^^^^^^^^^^^^^^^^^^^^ Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ Ρ‚ΠΈΠΏΠ°Ρ… Π²Ρ‹Π²Π΅Π΄Π΅Π½Π° Π½Π° 
//   основании сгСнСрированного ΠΊΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ссылаСтся ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠ΅
// Π½ΠΈΠΆΠ΅ условиС SELECT 
 
       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
//           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ сгСнСрированныС ΠΈΠΌΠ΅Π½Π°
       .from(ACTOR)
       .orderBy(1, 2)) {
    // ...
}

Kode kasebut digawe kanthi manual ing njaba bangunan, utawa kanthi manual ing saben bangunan. Contone, regenerasi kasebut bisa uga langsung sawise Migrasi database flyway, sing uga bisa ditindakake kanthi manual utawa otomatis.

Generasi kode sumber

Ana macem-macem filosofi, kaluwihan lan kekurangan sing ana gandhengane karo pendekatan iki kanggo nggawe kode - manual lan otomatis - sing ora bakal dakrembug kanthi rinci ing artikel iki. Nanging, umume, kabeh titik kode sing digawe yaiku ngidini sampeyan ngasilake "kabeneran" ing Jawa sing bisa ditindakake, ing njero sistem utawa ing njaba. Ing pangertèn, compiler sing ngasilake bytecode, kode mesin, utawa sawetara jinis kode liyane saka kode sumber nindakake perkara sing padha - kita entuk perwakilan saka "bebener" ing basa liya, tanpa alesan tartamtu.

Ana akeh generator kode kuwi. Tuladhane, XJC bisa ngasilake kode Java adhedhasar file XSD utawa WSDL. Prinsipe tansah padha:

  • Ana sawetara bebener (internal utawa eksternal) - contone, spesifikasi, model data, lsp.
  • Kita butuh perwakilan lokal babagan bebener iki ing basa pamrograman kita.

Kajaba iku, meh mesthi dianjurake kanggo ngasilake perwakilan kasebut - supaya ora redundansi.

Panyedhiya Tipe lan Pangolahan Anotasi

Cathetan: Pendekatan liyane, luwih modern lan spesifik kanggo nggawe kode kanggo jOOQ kalebu panggunaan panyedhiya jinis, kaya sing ditindakake ing F #. Ing kasus iki, kode digawe dening compiler, bener ing tataran kompilasi. Ing asas, kode kuwi ora ana ing wangun kode sumber. Ing Jawa, ana alat sing padha, sanajan ora kaya elegan - iki minangka prosesor anotasi, umpamane, lombok.

Ing pangertèn tartamtu, prekara sing padha kedadeyan ing kasus sing sepisanan, kajaba:

  • Sampeyan ora bisa ndeleng kode sing digawe (bisa uga kahanan iki ora katon banget kanggo wong liya?)
  • Sampeyan kudu mesthekake yen jinis bisa diwenehake, yaiku, "bener" kudu kasedhiya. Iki gampang ing kasus Lombok, sing nyatakake "kebenaran". Iku sethitik liyane angel karo model database sing gumantung ing sambungan urip sing tansah kasedhiya.

Apa masalah karo generasi kode?

Saliyane ing pitakonan angel carane iku luwih apik kanggo miwiti kode generasi - kanthi manual utawa otomatis, Aku kudu sebutno sing ana wong sing pracaya generasi kode ora perlu ing kabeh. Kabeneran kanggo sudut pandang iki, sing paling kerep dakwenehi, yaiku angel nyiyapake pipa mbangun. Ya angel tenan. Ana biaya infrastruktur tambahan. Yen sampeyan lagi miwiti karo produk tartamtu (kaya jOOQ, utawa JAXB, utawa Hibernate, etc.), butuh wektu kanggo nyiyapake workbench sing pengin sampeyan gunakake sinau API dhewe kanggo entuk nilai saka iku. .

Yen biaya sing digandhengake karo pangerten piranti generator dhuwur banget, banjur, tenan, API nindakake proyek miskin ing migunani saka generator kode (lan ing mangsa dadi metu sing pangaturan dhewe uga angel). Kegunaan kudu dadi prioritas paling dhuwur kanggo API kasebut. Nanging iki mung siji argumen nglawan generasi kode. Yen ora, tulis kabeh kanthi tangan perwakilan lokal saka bebener internal utawa eksternal.

Akeh sing bakal ngomong yen dheweke ora duwe wektu kanggo nindakake kabeh iki. Padha ing deadline kanggo Super Product sing. Ing sawijining dina mengko kita bakal nyisir konveyor perakitan, kita bakal duwe wektu. Aku bakal mangsuli:

Bebener pisanan, utawa kenapa sistem kudu dirancang adhedhasar struktur database
Asli, Alan O'Rourke, Tumpukan Pemirsa

Nanging ing Hibernate / JPA gampang banget kanggo nulis kode "ing Jawa".

tenan. Kanggo Hibernate lan pangguna, iki minangka anugerah lan kutukan. Ing Hibernate, sampeyan mung bisa nulis sawetara entitas, kaya iki:

	@Entity
class Book {
  @Id
  int id;
  String title;
}

Lan meh kabeh wis siyap. Saiki akeh Hibernate yaiku ngasilake "rincian" rumit babagan kepiye entitas iki bakal ditetepake ing DDL saka "dialek" SQL sampeyan:

	CREATE TABLE book (
  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
  title VARCHAR(50),
 
  CONSTRAINT pk_book PRIMARY KEY (id)
);
 
CREATE INDEX i_book_title ON book (title);

... lan miwiti mbukak aplikasi. Fitur sing apik banget kanggo tangi lan mlaku kanthi cepet lan nyoba macem-macem.

Nanging, mugi kula. Aku ngapusi.

  • Apa Hibernate bakal ngetrapake definisi kunci utama sing dijenengi iki?
  • Apa Hibernate nggawe indeks ing TITLE? Aku ngerti manawa kita butuh.
  • Apa Hibernate bakal nggawe kunci iki minangka kunci identitas ing Spesifikasi Identitas?

Mbokmenawa ora. Yen sampeyan ngembangake proyek sampeyan saka awal, mesthine trep kanggo mbuwang database lawas lan ngasilake sing anyar sanalika sampeyan nambah anotasi sing dibutuhake. Dadi, entitas Buku pungkasane bakal dadi:

	@Entity
@Table(name = "book", indexes = {
  @Index(name = "i_book_title", columnList = "title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
  String title;
}

Kelangan. regenerasi. Maneh, ing kasus iki, bakal gampang banget ing wiwitan.

Nanging mengko sampeyan kudu mbayar.

Cepet utawa mengko sampeyan kudu pindhah menyang produksi. Nalika iku model mandheg kerja. Amarga:

Ing produksi, ora bisa maneh, yen perlu, mbusak database lawas lan miwiti kabeh saka awal. Database sampeyan bakal dadi warisan.

Wiwit saiki lan ing salawas-lawase sampeyan kudu nulis Skrip migrasi DDL, contone, nggunakake Flyway. Lan apa sing bakal kedadeyan karo entitas sampeyan ing kasus iki? Sampeyan bisa ngatur kanthi manual (lan pindho beban kerja sampeyan) utawa nggawe Hibernate regenerasi kanggo sampeyan (kemungkinan sing digawe kanthi cara iki kanggo nyukupi pangarepan sampeyan?) Sampeyan bakal ilang.

Mangkono, sanalika sampeyan pindhah menyang produksi, sampeyan butuh patch panas. Lan kudu digawa menyang produksi kanthi cepet. Amarga sampeyan durung nyiapake lan ngatur pipelining lancar saka migrasi kanggo produksi, sampeyan lagi patching wildly. Banjur sampeyan ora duwe wektu kanggo nindakake kabeh kanthi bener. Lan sampeyan ngejar Hibernate, amarga iku mesthi salah sapa wae, nanging dudu sampeyan ...

Nanging, wiwit wiwitan, kabeh bisa ditindakake kanthi beda. Contone, sijine rodha bunder ing sepedha.

Database pisanan

"Bebener" sing nyata ing skema database lan "kedaulatan" sampeyan ana ing basis data. Skema kasebut mung ditetepake ing basis data dhewe lan ora ana ing papan liya, lan saben klien duwe salinan skema iki, saengga nggawe pangertèn sing sampurna kanggo ngetrapake ketaatan marang skema lan integritas, kanggo nindakake kanthi bener ing basis data - ing ngendi informasi disimpen.
Iki wis lawas malah kawicaksanan hackneyed. Tombol utami lan unik apik. Kunci asing apik. Priksa kendala apik. Pratelan - Nggih.

Lan, ora mung kuwi. Contone, nggunakake Oracle, sampeyan bisa uga pengin nemtokake:

  • Apa tablespace ing meja sampeyan
  • Apa nilai PCTFREE dheweke
  • Apa ukuran cache ing urutan sampeyan (ing mburi id)

Kabeh iki bisa uga ora masalah ing sistem cilik, nanging ora perlu ngenteni nganti transisi menyang wilayah "data amba" - sampeyan bisa miwiti entuk manfaat saka optimasi panyimpenan sing disedhiyakake vendor, kayata sing kasebut ing ndhuwur, luwih dhisik. Ora ana ORM sing dakdeleng (kalebu jOOQ) nyedhiyakake akses menyang pilihan DDL lengkap sing sampeyan pengin digunakake ing database sampeyan. ORM nawakake sawetara alat kanggo mbantu sampeyan nulis DDL.

Nanging ing pungkasan dina, skema sing dirancang kanthi apik ditulis tangan ing DDL. Sembarang DDL sing digawe mung kira-kira.

Kepiye model klien?

Kaya kasebut ing ndhuwur, ing klien sampeyan butuh salinan skema database, tampilan klien. Ora perlu dikandhakake, tampilan klien iki kudu selaras karo model nyata. Apa cara sing paling apik kanggo nggayuh iki? Kanthi generator kode.

Kabeh database nyedhiyakake meta-informasi liwat SQL. Mangkene carane njupuk kabeh tabel ing macem-macem dialek SQL saka database sampeyan:

	-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server
SELECT table_schema, table_name
FROM information_schema.tables
 
-- DB2
SELECT tabschema, tabname
FROM syscat.tables
 
-- Oracle
SELECT owner, table_name
FROM all_tables
 
-- SQLite
SELECT name
FROM sqlite_master
 
-- Teradata
SELECT databasename, tablename
FROM dbc.tables

Pitakon iki (utawa sing padha, gumantung apa sampeyan uga kudu nimbang tampilan, tampilan materialized, fungsi tabel-nilai) uga dieksekusi kanthi nelpon DatabaseMetaData.getTables() saka JDBC, utawa nggunakake jOOQ meta-modul.

Saka asil pitakon kasebut, relatif gampang kanggo ngasilake perwakilan sisih klien saka model database sampeyan, apa wae teknologi sing sampeyan gunakake ing klien.

  • Yen sampeyan nggunakake JDBC utawa Spring, sampeyan bisa nggawe set konstanta senar
  • Yen sampeyan nggunakake JPA, sampeyan bisa ngasilake entitas kasebut dhewe
  • Yen sampeyan nggunakake jOOQ sampeyan bisa ngasilake model meta jOOQ

Gumantung saka kemampuan API klien sampeyan (umpamane jOOQ utawa JPA), model meta sing digawe bisa dadi sugih lan lengkap. Njupuk, contone, kamungkinan gabung implisit, dipuntepangaken ing jOOQ 3.11, sing gumantung ing meta-informasi babagan hubungan kunci asing ing antarane tabel sampeyan.

Saiki tambahan basis data bakal nganyari kode klien kanthi otomatis. Mbayangno contone:

ALTER TABLE book RENAME COLUMN title TO book_title;

Apa sampeyan pengin nindakake proyek iki kaping pindho? Ora ana kasus. Kita mung nindakake DDL, mbukak liwat pipa mbangun, lan entuk entitas sing dianyari:

@Entity
@Table(name = "book", indexes = {
 
  // Π’Ρ‹ ΠΎΠ± этом Π·Π°Π΄ΡƒΠΌΡ‹Π²Π°Π»ΠΈΡΡŒ?
  @Index(name = "i_book_title", columnList = "book_title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
 
  @Column("book_title")
  String bookTitle;
}

Utawa kelas jOOQ sing dianyari. Umume owah-owahan DDL uga mengaruhi semantik, ora mung sintaksis. Mulane, bisa uga trep kanggo ndeleng ing kode kompilasi kode apa sing bakal (utawa bisa) kena pengaruh kanthi nambah basis data sampeyan.

Mung bebener

Preduli saka teknologi sing sampeyan gunakake, mesthi ana model siji-sijine sumber bebener kanggo sawetara subsistem - utawa paling ora kita kudu ngupayakake iki lan ngindhari kebingungan perusahaan ing endi "bebener" ana ing endi wae lan ora ana ing endi wae. Kabeh bisa dadi luwih gampang. Yen sampeyan mung ngganti file XML karo sawetara sistem liyane, mung nggunakake XSD. Deleng model meta INFORMATION_SCHEMA jOOQ ing wangun XML:
https://www.jooq.org/xsd/jooq-meta-3.10.0.xsd

  • XSD uga dimangerteni
  • XSD nandhani konten XML kanthi apik lan ngidini validasi ing kabeh basa klien
  • XSD versi apik lan kompatibel banget
  • XSD bisa diterjemahake menyang kode Jawa nggunakake XJC

Titik pungkasan iku penting. Nalika sesambungan karo sistem eksternal nggunakake pesen XML, kita pengin mesthekake yen pesen kita bener. Iki gampang banget digayuh karo JAXB, XJC lan XSD. Iku bakal Edan gedhine kanggo mikir sing, ing pendekatan desain Jawa-pisanan ngendi kita nggawe pesen kita minangka obyek Jawa, padha bisa piye wae render intelligible kanggo XML lan dikirim kanggo konsumsi kanggo sistem liyane. XML sing digawe kanthi cara iki bakal dadi kualitas sing ora apik, ora duwe dokumen, lan angel dikembangake. Yen ana persetujuan ing tingkat kualitas layanan (SLA) ing antarmuka kuwi, kita bakal langsung meneng.

Jujur, iki persis sing kedadeyan karo API JSON, nanging iki crita liyane, aku bakal mbantah wektu sabanjure ...

Database: padha

Nggarap database, sampeyan ngerti yen kabeh padha ing dasare. Basis data nduweni data lan kudu ngatur skema kasebut. Sembarang modifikasi sing digawe kanggo skema kudu dileksanakake langsung ing DDL supaya sumber siji bebener dianyari.

Nalika nganyari sumber wis kedadeyan, kabeh klien uga kudu nganyari salinan model kasebut. Sawetara klien bisa uga ditulis ing Jawa nggunakake jOOQ lan Hibernate utawa JDBC (utawa loro-lorone). Klien liyane bisa uga ditulis ing Perl (ayo muga-muga sukses), liyane ing C #. Ora masalah. Model utama ana ing database. Model sing digawe ORM biasane kualitase ora apik, dokumentasi sing kurang apik, lan angel dikembangake.

Mula aja nganti salah. Aja nggawe kesalahan saka wiwitan. Bisa saka database. Mbangun pipa penyebaran sing bisa otomatis. Aktifake generator kode kanggo nyalin model database kanthi gampang lan mbucal menyang klien. Lan aja kuwatir babagan generator kode. Padha apik. Kanthi dheweke, sampeyan bakal dadi luwih produktif. Sampeyan mung kudu nglampahi sawetara wektu nyetel munggah saka wiwitan, lan sampeyan bakal duwe kinerja apik taun kanggo mbangun crita project.

Aja matur nuwun, mengko.

Panjelasan

Dadi cetha: Artikel iki ora kanthi cara apa wae nganjurake yen kabeh sistem (yaiku domain, logika bisnis, dsb., dsb.) kudu flexed supaya pas karo model database sampeyan. Apa sing dakkandhakake ing artikel iki yaiku kode klien sing sesambungan karo database kudu tumindak adhedhasar model database supaya ora ngasilake model database ing status "kelas pertama". Logika kasebut biasane ana ing lapisan akses data ing klien sampeyan.

Ing arsitektur rong tingkat, sing isih dilestarekake ing sawetara panggonan, model sistem kasebut bisa uga mung siji. Nanging, ing paling sistem, lapisan akses data misale jek kula minangka "subsistem" sing encapsulates model database.

Pangecualian

Ana pangecualian kanggo saben aturan, lan aku wis ngandika sadurunge sing database pisanan lan pendekatan generasi kode sumber kadhangkala bisa cecek. Ing ngisor iki sawetara pangecualian kasebut (mbok menawa ana liyane):

  • Nalika skema ora dingerteni lan kudu dibukak. Contone, sampeyan nyedhiyakake alat kanggo mbantu pangguna navigasi diagram apa wae. Phew. Ora ana generasi kode ing kene. Nanging isih - database pisanan kabeh.
  • Nalika sirkuit kudu kui ing fly kanggo ngatasi sawetara masalah. Conto iki misale jek versi rada frilly saka pola nilai atribut entitas, yaiku, sampeyan ora duwe skema sing jelas. Ing kasus iki, sampeyan asring ora bisa yakin manawa RDBMS bakal cocog karo sampeyan.

Pangecualian kanthi alam luar biasa. Umume kasus sing nggunakake RDBMS, skema kasebut dikenal luwih dhisik, ana ing njero RDBMS lan minangka siji-sijine sumber "bebener", lan kabeh klien kudu entuk salinan sing asale saka iku. Saenipun, iki kudu ndherek generator kode.

Source: www.habr.com

Add a comment