真実が先、぀たりなぜデヌタベヌス構造に基づいおシステムを蚭蚈する必芁があるのか

おい、ハブル

私たちはこのテヌマに぀いお研究を続けおいたす Java О 春デヌタベヌスレベルも含めお。 今日は、倧芏暡なアプリケヌションを蚭蚈するずきに、決定的に重芁なのは Java コヌドではなくデヌタベヌス構造である理由、これがどのように行われるか、そしおこの芏則にはどのような䟋倖があるのか​​に぀いお読んでいただくこずをお勧めしたす。

このかなり遅れた蚘事では、ほずんどすべおの堎合、アプリケヌションのデヌタ モデルは「Java の機胜」(たたは䜿甚しおいるクラむアント蚀語) ではなく「デヌタベヌス」に基づいお蚭蚈されるべきであるず私が考える理由を説明したす。䞀緒に働く。 XNUMX 番目のアプロヌチを取るず、プロゞェクトが成長し始めるず、痛みず苊しみの長い道を歩むこずになりたす。

この蚘事は以䞋をもずに曞かれたした 䞀぀の質問、スタックオヌバヌフロヌで䞎えられたす。

reddit での興味深いディスカッションをセクションごずにたずめたもの /r/java О / r / programming.

コヌド生成

jOOQ のこずをよく知っおいお、jOOQ が゜ヌス コヌド生成に倧きく䟝存しお動䜜しおいるずいう事実に激怒しおいるナヌザヌが非垞に少数であるこずに、私はずおも驚きたした。 あなたが適切だず思う jOOQ を䜿甚するこずを誰も止めたり、コヌド生成の䜿甚を匷制したりする人はいたせん。 しかし、jOOQ を扱うデフォルトの (マニュアルに蚘茉されおいる) 方法では、(レガシヌ) デヌタベヌス スキヌマから開始し、jOOQ コヌド ゞェネレヌタヌを䜿甚しおそれをリバヌス ゚ンゞニアリングし、それによっおテヌブルを衚すクラスのセットを取埗し、型を曞き蟌みたす。 -これらのテヌブルに察する安党なク゚リ:

	for (Record2<String, String> record : DSL.using(configuration)
//   ^^^^^^^^^^^^^^^^^^^^^^^ ИМфПрЌацОя П тОпах вывеЎеМа Ма 
//   ПсМПваМОО сгеМерОрПваММПгП кПЎа, Ма кПтПрый ссылается прОвеЎеММПе
// МОже услПвОе SELECT 
 
       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
//           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ сгеМерОрПваММые ОЌеМа
       .from(ACTOR)
       .orderBy(1, 2)) {
    // ...
}

コヌドはアセンブリの倖郚で手動で生成されるか、各アセンブリで手動で生成されたす。 たずえば、そのような再生は、 Flyway デヌタベヌスの移行 (手動たたは自動で行うこずもできたす).

゜ヌスコヌドの生成

コヌド生成 (手動および自動) に察するこれらのアプロヌチには、さたざたな哲孊、長所ず短所がありたすが、この蚘事では詳しく説明したせん。 しかし、䞀般に、生成されたコヌドの重芁な点は、システム内たたはシステム倖で、私たちが圓たり前だず思っおいる「真実」を Java で再珟できるずいうこずです。 ある意味、これはコンパむラがバむトコヌド、マシンコヌド、たたはその他の圢匏の゜ヌスコヌドを生成するずきに行うこずです。特定の理由に関係なく、私たちは「真実」を別の蚀語で衚珟したす。

このようなコヌドゞェネレヌタヌはたくさんありたす。 䟋えば、 XJC は XSD たたは WSDL ファむルに基づいお Java コヌドを生成できたす。 原則は垞に同じです。

  • 䜕らかの真実 (内郚たたは倖郚) が存圚したす。たずえば、仕様、デヌタモデルなどです。
  • この真実をプログラミング蚀語でロヌカルに衚珟する必芁がありたす。

さらに、冗長性を避けるために、そのような衚珟を生成するこずがほずんどの堎合掚奚されたす。

タむププロバむダヌずアノテヌション凊理

泚: jOOQ のコヌドを生成する別の、より珟代的で具䜓的なアプロヌチは、タむプ プロバむダヌを䜿甚するこずです。 F# で実装されおいるため、。 この堎合、コヌドはコンパむラによっお、実際にはコンパむル段階で生成されたす。 原則ずしお、そのようなコヌドは゜ヌス圢匏では存圚したせん。 Java には、それほど゚レガントではありたせんが、同様のツヌル (アノテヌション プロセッサなど) がありたす。 チリ.

ある意味では、ここでも最初のケヌスず同じこずが起こりたすが、次の点が異なりたす。

  • 生成されたコヌドは衚瀺されたせん (おそらく、この状況にあたり䞍快感を感じない人もいるでしょうか?)
  • 型を提䟛できるこずを確認する必芁がありたす。぀たり、「true」が垞に䜿甚可胜である必芁がありたす。 「真実」に泚釈を付けるロンボク島の堎合、これは簡単です。 垞に利甚可胜なラむブ接続に䟝存するデヌタベヌス モデルの堎合は、少し耇雑になりたす。

コヌド生成の問題は䜕ですか?

コヌド生成を手動たたは自動で実行するのに最適な方法ずいう難しい問題に加えお、コヌド生成はたったく必芁ないず信じおいる人がいるこずにも蚀及しなければなりたせん。 この芳点の正圓化は、私が最も頻繁に遭遇したこずですが、ビルド パむプラむンをセットアップするのが難しいずいうこずです。 はい、本圓に難しいです。 远加のむンフラストラクチャコストが発生したす。 特定の補品 (jOOQ、JAXB、Hibernate など) を䜿い始めたばかりの堎合、実皌働環境のセットアップには時間がかかるため、そこから䟡倀を匕き出すために API 自䜓の孊習に時間を費やしたほうがよいでしょう。 。

ゞェネレヌタヌの構造を理解するこずに関連するコストが高すぎる堎合、確かに、API はコヌド ゞェネレヌタヌの䜿いやすさに関しお䞍十分な仕事をしおいたずいうこずになりたす (そしお、その埌、コヌド ゞェネレヌタヌでのナヌザヌのカスタマむズも難しいこずが刀明したした)。 このような API では、䜿いやすさが最優先される必芁がありたす。 しかし、これはコヌド生成に察する反論の XNUMX ぀にすぎたせん。 それ以倖の堎合、内郚たたは倖郚の真実のロヌカル衚珟を蚘述するのは完党に手動です。

倚くの人は、これすべおを行う時間がないず蚀うでしょう。 圌らはスヌパヌプロダクトの期限を過ぎおいたす。 い぀か組み立おコンベアを敎理敎頓したす、時間はありたす。 私はそれらに答えたす

真実が先、぀たりなぜデヌタベヌス構造に基づいおシステムを蚭蚈する必芁があるのか
オリゞナル, アラン・オルヌク、オヌディ゚ンス・スタック

しかし、Hibernate/JPA では Java コヌドを曞くのはずおも簡単です。

本圓に。 Hibernate ずそのナヌザヌにずっお、これは祝犏でもあり、呪いでもありたす。 Hibernate では、次のようにいく぀かの゚ンティティを簡単に曞くこずができたす。

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

そしおほがすべおの準備が敎いたした。 この゚ンティティが SQL 「方蚀」の DDL でどのように正確に定矩されるかに぀いおの耇雑な「詳现」を生成するのは、Hibernate の圹割です。

	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);

...そしおアプリケヌションの実行を開始したす。 すぐに始めおさたざたなこずを詊すには非垞に玠晎らしい機䌚です。

ただし、お蚱しください。 うそを぀いおいた。

  • Hibernate は実際にこの名前付き䞻キヌの定矩を匷制したすか?
  • Hibernate は TITLE にむンデックスを䜜成したすか? – それが必芁になるこずは確かです。
  • Hibernate はこのキヌを ID 仕様で正確に識別するのでしょうか?

おそらくそうではありたせん。 プロゞェクトを最初から開発しおいる堎合は、叀いデヌタベヌスを単玔に砎棄し、必芁な泚釈を远加したらすぐに新しいデヌタベヌスを生成するず䟿利です。 したがっお、Book ゚ンティティは最終的に次の圢匏になりたす。

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

いいね。 再生したす。 この堎合も、最初は非垞に簡単です。

でも埌でお金を支払わなければなりたせん

遅かれ早かれ、本番環境に移行する必芁がありたす。 その時点でこのモデルは機胜しなくなりたす。 なぜなら

運甚環境では、必芁に応じお叀いデヌタベヌスを砎棄しお最初から開始するこずはできなくなりたす。 デヌタベヌスはレガシヌになりたす。

これからも氞遠に、あなたは曞かなければなりたせん DDL 移行スクリプト (Flyway を䜿甚したものなど)。 この堎合、あなたの゚ンティティはどうなるでしょうか? これらを手動で適応させる (぀たり、ワヌクロヌドが XNUMX 倍になる) か、Hibernate にそれらを再生成するように指瀺する (この方法で生成されたものが期埅に応えられる可胜性はどのくらいでしょうか?) どちらにしおも、負けです。

したがっお、運甚を開始したら、ホット パッチが必芁になりたす。 そしお、それらは非垞に迅速に本番環境に導入される必芁がありたす。 準備をしおおらず、本番環境ぞの移行のスムヌズなパむプラむンを敎理しおいなかったため、すべおに乱暎にパッチを圓おおいたす。 そしお、すべおを正しく行う時間はもうありたせん。 そしおあなたは Hibernate を批刀したす。それは垞に誰かのせいであり、あなただけではないからです...

むしろ、最初からたったく異なるやり方で物事を進めるこずもできたはずです。 たずえば、自転車に䞞い車茪を付けたす。

デヌタベヌスが先

デヌタベヌス スキヌマの本圓の「真実」ずそれに察する「䞻暩」はデヌタベヌス内にありたす。 スキヌマはデヌタベヌス自䜓でのみ定矩され、他の堎所では定矩されず、各クラむアントはこのスキヌマのコピヌを持っおいるため、スキヌマぞの準拠ずその敎合性を匷制し、情報が保存されおいるデヌタベヌス内で正しく実行するこずは完党に理にかなっおいたす。保管されおいたす。
これは叀くおありきたりな知恵です。 䞻キヌず䞀意キヌは適切です。 倖郚キヌは䟿利です。 制限を確認するのは良いこずです。 アサヌション - 倧䞈倫。

さらに、それだけではありたせん。 たずえば、Oracle を䜿甚する堎合は、次のように指定するずよいでしょう。

  • テヌブルはどのテヌブルスペヌスにありたすか?
  • PCTFREE 倀はどれくらいですか?
  • シヌケンス内のキャッシュ サむズ (ID の埌ろ) はどれくらいですか?

これは小芏暡システムでは重芁ではないかもしれたせんが、ビッグ デヌタ領域に移行するたで埅぀必芁はありたせん。䞊蚘のようなベンダヌ提䟛のストレヌゞ最適化の恩恵をより早く受け始めるこずができたす。 私が芋た ORM (jOOQ を含む) のどれも、デヌタベヌスで䜿甚する必芁がある DDL オプションの完党なセットぞのアクセスを提䟛したせんでした。 ORM は、DDL の䜜成に圹立぀いく぀かのツヌルを提䟛したす。

しかし、結局のずころ、適切に蚭蚈された回路は DDL で手曞きで䜜成されたす。 生成された DDL は、その近䌌倀にすぎたせん。

クラむアントモデルに぀いおはどうですか?

䞊で述べたように、クラむアントではデヌタベヌス スキヌマのコピヌ、クラむアント ビュヌが必芁になりたす。 蚀うたでもなく、このクラむアント ビュヌは実際のモデルず同期しおいる必芁がありたす。 これを達成するための最善の方法は䜕でしょうか? コヌドゞェネレヌタヌを䜿甚する。

すべおのデヌタベヌスは SQL 経由でメタ情報を提䟛したす。 さたざたな SQL 蚀語でデヌタベヌスからすべおのテヌブルを取埗する方法は次のずおりです。

	-- 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

これらのク゚リ (たたは、ビュヌ、マテリアラむズド ビュヌ、テヌブル倀関数も考慮する必芁があるかどうかに応じお同様のク゚リ) も、呌び出しによっお実行されたす。 DatabaseMetaData.getTables() JDBC から、たたは jOOQ メタモゞュヌルを䜿甚したす。

このようなク゚リの結果から、クラむアントでどのようなテクノロゞを䜿甚しおいるかに関係なく、デヌタベヌス モデルのクラむアント偎衚珟を生成するのは比范的簡単です。

  • JDBC たたは Spring を䜿甚しおいる堎合は、文字列定数のセットを䜜成できたす。
  • JPAを䜿甚するず゚ンティティ自䜓を生成できたす
  • jOOQ を䜿甚するず、jOOQ メタモデルを生成できたす。

クラむアント API (jOOQ や JPA など) によっお提䟛される機胜の量に応じお、生成されるメタ モデルは非垞に豊富で完党なものになる可胜性がありたす。 たずえば、暗黙的な結合の可胜性を考えおみたしょう。 jOOQ 3.11 で導入、テヌブル間に存圚する倖郚キヌ関係に぀いお生成されたメタ情報に䟝存したす。

これで、デヌタベヌスが増加するず、クラむアント コヌドが自動的に曎新されたす。 たずえば次のこずを想像しおください。

ALTER TABLE book RENAME COLUMN title TO book_title;

本圓にこの仕事を XNUMX 回やりたいですか? どんな堎合にも。 DDL をコミットし、ビルド パむプラむンを通じお実行し、曎新された゚ンティティを取埗するだけです。

@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;
}

たたは曎新された jOOQ クラス。 ほずんどの DDL 倉曎は、構文だけでなくセマンティクスにも圱響したす。 したがっお、コンパむルされたコヌドを調べお、どのコヌドがデヌタベヌスの増分によっお圱響を受ける (たたは圱響を受ける可胜性がある) かを確認するず䟿利です。

唯䞀の真実

どのようなテクノロゞを䜿甚するかに関係なく、サブシステムにずっお唯䞀の真実の情報源ずなるモデルは垞に XNUMX ぀ありたす。あるいは、少なくずもこれを目指しお努力し、「真実」がどこにでも存圚し、同時にはどこにも存圚しないような䌁業の混乱を避ける必芁がありたす。 。 すべおがもっずシンプルになる可胜性がありたす。 XML ファむルを他のシステムず亀換するだけの堎合は、XSD を䜿甚しおください。 jOOQ の INFORMATION_SCHEMA メタモデルを XML 圢匏で芋おみたしょう。
https://www.jooq.org/xsd/jooq-meta-3.10.0.xsd

  • XSD はよく理解されおいたす
  • XSD は XML コンテンツを適切にトヌクン化し、すべおのクラむアント蚀語での怜蚌を可胜にしたす
  • XSD は適切にバヌゞョン管理されおおり、高床な䞋䜍互換性を備えおいたす
  • XSD は、XJC を䜿甚しお Java コヌドに倉換できたす

最埌の点が重芁です。 XML メッセヌゞを䜿甚しお倖郚システムず通信する堎合、メッセヌゞが有効であるこずを確認する必芁がありたす。 これは、JAXB、XJC、XSD を䜿甚するず非垞に簡単に実珟できたす。 メッセヌゞを Java オブゞェクトずしお䜜成する「Java ファヌスト」蚭蚈アプロヌチを䜿甚しお、メッセヌゞを䜕らかの圢で䞀貫しお XML にマッピングし、別のシステムに送信しお消費できるず考えるのはたったくの狂気でしょう。 この方法で生成された XML は品質が非垞に䜎く、文曞化されおおらず、開発が困難です。 このようなむンタヌフェむスにサヌビス レベル アグリヌメント (SLA) があった堎合、私たちはすぐにそれを台無しにするでしょう。

正盎なずころ、これは JSON API では垞に起こっおいるこずですが、それはたた別の話です。次回は喧嘩したす...

デヌタベヌス: それらは同じものです

デヌタベヌスを操䜜するず、それらはすべお基本的に䌌おいるこずがわかりたす。 基地はそのデヌタを所有しおおり、スキヌムを管理する必芁がありたす。 唯䞀の信頌できる情報源が曎新されるように、スキヌマに加えた倉曎はすべお DDL に盎接実装する必芁がありたす。

゜ヌスの曎新が行われるず、すべおのクラむアントはモデルのコピヌも曎新する必芁がありたす。 䞀郚のクラむアントは、jOOQ ず Hibernate たたは JDBC (あるいはその䞡方) を䜿甚しお Java で䜜成できたす。 他のクラむアントは Perl で䜜成できたすが (成功を祈るばかりです)、他のクラむアントは C# で䜜成できたす。 それは問題ではありたせん。 メむンモデルはデヌタベヌス内にありたす。 ORM を䜿甚しお生成されたモデルは通垞、品質が䜎く、文曞化が䞍十分で、開発が困難です。

だから、間違いを犯さないでください。 最初から間違えないようにしたしょう。 デヌタベヌスから䜜業したす。 自動化できるデプロむメント パむプラむンを構築したす。 コヌド ゞェネレヌタヌを有効にするず、デヌタベヌス モデルを簡単にコピヌしおクラむアントにダンプできるようになりたす。 コヌドゞェネレヌタヌに぀いお心配するのはもうやめたしょう。 圌らは良い。 これらを䜿甚するず、生産性がさらに向䞊したす。 最初からそれらをセットアップするのに少し時間を費やすだけで枈みたす。そうすれば、䜕幎にもわたる生産性の向䞊が埅っおおり、それがプロゞェクトの歎史を䜜り䞊げるこずになりたす。

ただ感謝しないでください、埌で。

明確化

明確にしおおきたす: この蚘事は、デヌタベヌス モデルに合わせおシステム党䜓 (぀たり、ドメむン、ビゞネス ロゞックなど) を倉曎する必芁があるず䞻匵するものではありたせん。 この蚘事で私が蚀いたいのは、デヌタベヌスず察話するクラむアント コヌドは、デヌタベヌス モデルに基づいお動䜜する必芁があるため、それ自䜓がデヌタベヌス モデルを「ファヌストクラス」の状態で再珟しないようにする必芁があるずいうこずです。 このロゞックは通垞、クラむアントのデヌタ アクセス局にありたす。

いく぀かの堎所でただ保存されおいる XNUMX レベルのアヌキテクチャでは、そのようなシステム モデルが唯䞀可胜なものである可胜性がありたす。 ただし、ほずんどのシステムでは、デヌタ アクセス局はデヌタベヌス モデルをカプセル化する「サブシステム」であるように私には思えたす。

䟋倖

すべおのルヌルには䟋倖があり、デヌタベヌス優先で゜ヌスコヌド生成のアプロヌチが䞍適切な堎合があるこずはすでに述べたした。 以䞋にそのような䟋倖をいく぀か瀺したす (おそらく他にもあるでしょう)。

  • スキヌマが䞍明であり、怜出する必芁がある堎合。 たずえば、あなたは、ナヌザヌが任意の図をナビゲヌトできるようにするツヌルのプロバむダヌであるずしたす。 うヌん。 ここではコヌド生成は行われたせん。 しかし、それでもデヌタベヌスが最優先です。
  • 問題を解決するために回路をオンザフラむで生成する必芁がある堎合。 この䟋は、パタヌンの少し空想的なバヌゞョンのように芋えたす。 ゚ンティティの属性倀぀たり、明確に定矩されたスキヌムが実際にはありたせん。 この堎合、RDBMS が自分に適しおいるかどうかさえ確信が持おないこずがよくありたす。

䟋倖は本質的に䟋倖的なものです。 RDBMS の䜿甚に関するほずんどの堎合、スキヌマは事前にわかっおおり、スキヌマは RDBMS 内に存圚し、「真実」の唯䞀の情報源であり、すべおのクラむアントはスキヌマから掟生したコピヌを取埗する必芁がありたす。 理想的には、コヌドゞェネレヌタヌを䜿甚する必芁がありたす。

出所 habr.com

コメントを远加したす