モノリシックアーキテクチャから分散データ永続化へ、ORMフレームワークMybatis

モノリシックアーキテクチャから分散データ永続化へ、ORMフレームワークMybatis

[[377400]]

この記事はWeChatの公開アカウント「Uncle Who Knows a Little Code」から転載したもので、著者はUncle Who Knows a Little Codeです。この記事を転載する場合は、Uncle Who Knows Codeの公式アカウントまでご連絡ください。

1 プレコンセプト

01 粘り強さ

永続性とは、ディスクなどの永続的に保存できるストレージ デバイスにデータを保存することを意味します。

02 JDBC

Java を学習する場合、ほとんどのプログラマーは、Java を使用してデータベースにアクセスする方法を学ぶときに、最初に JDBC を学習します。 JDBC は、SQL ステートメントを実行し、データベースへの統一されたアクセスを提供し、データベースにデータを「保持」するために使用される Java API です。

簡単に説明しましょう (JDBC についてある程度の知識がある方は読み飛ばしてください)。

Sun は 1998 年に JDK1.1 をリリースしました。JDBC はこのバージョンにおける重要な技術ポイントです。 Java 言語を使用してデータベースに接続する場合、通常は、Sun がデータベースへの接続方法と SQL ステートメントの実行方法を実現すると考えられています。しかし、市場にはデータベースが多すぎて、データベース間の違いも非常に大きくなっています。さらに、Sun が各データベースの内部詳細を理解することは不可能です...

Java コードがデータベースにうまく接続できるようにするために、Sun は一連のインターフェースを開発しました。インターフェースと呼ばれていますが、実際には一連の標準と仕様です。コードの具体的な実装は各データベースベンダーによって作成されます。したがって、私たちがよく呼ぶ「ドライバー クラス」は、各ベンダーの実装クラスです。

したがって、JDBC を使用してデータベースに接続する場合、最初のステップはドライバーを登録すること、つまり、使用するデータベース実装クラスを JVM に指示することです。

03 オーム

ORM フレームワークが登場する前は、次のようにデータベースを操作していました。

JDBC を使用してデータベースを操作する場合、コードが煩雑になり、SQL のパラメータのスペルにエラーが発生しやすくなり、読みやすさが悪くなるため、コードのメンテナンスが難しくなることがわかります。

ORM フレームワークを使用すると、データベースを次のように操作します。

ORM フレームワークは、Java オブジェクトとデータベース テーブル間のマッピングを作成し、データベース アクセスの詳細をカプセル化します。データベースステートメントを操作する必要がある場合は、Java オブジェクトを直接操作できます。

2. Spring BootはMyBatisを統合する

Java でよく使用される ORM フレームワークには、Hibernate、MyBatis、JPA などがあります。次のテキストでは、これらのフレームワークの長所と短所を比較します。この章では、主に、Spring Boot プロジェクトに MyBatis を統合してデータベースにアクセスする方法について説明します。

ステップ1.依存関係を追加する

  1. <依存関係>
  2. <グループID>mysql</グループID>
  3. <artifactId>mysql-コネクタ-java</artifactId>
  4. </依存関係>
  5.  
  6. <依存関係>
  7. <グループ ID>org.mybatis.spring.boot</グループ ID>
  8. <artifactId>mybatis-spring-boot-starter</artifactId>
  9. <バージョン>2.0.1</バージョン>
  10. </依存関係>

ステップ2. データベースリンクを構成する

application.yml ファイルでデータベース関連情報を構成します。

  1. #データソースの構成
  2. 春:
  3. データソース:
  4. #データベースドライバー
  5. ドライバークラス: com.mysql.cj.jdbc.Driver
  6. #データベース URL
  7. URL: jdbc:mysql://127.0.0.1:3306/arch?characterEncoding=UTF-8&serverTimezone=UTC
  8. #ユーザー名
  9. ユーザー名: root
  10. #パスワード
  11. パスワード: root

ステップ3. データベースリンクを構成する

ローカル データベースで、ユーザー テーブルを作成し、データを挿入します。

  1. 作成する テーブルが存在しない場合は` user` (
  2. `id` INT UNSIGNED AUTO_INCREMENT、
  3. `userid` VARCHAR (100) NOT   NULL
  4. `username` VARCHAR (100) NOT   NULL
  5. `性別` CHAR (1) NOT   NULL
  6. `年齢` INT  ない  NULL
  7. 主要な キー( `id` )
  8. )ENGINE=InnoDBデフォルト文字セット=utf8;
  9.  
  10. 入れる の中へ ユーザー(ユーザーID、ユーザー名、性別、年齢) 'dashu' 'Uncle' 'M' 、18);

ステップ4. モデルレイヤーを作成する

通常、データベースからデータを受け取るオブジェクトの場合は、別のモデル パッケージを作成し、クラス内の属性とフィールドを同じに保つことに慣れています。

  1. パッケージ com.archevolution.chapter4.model;
  2.  
  3. パブリッククラスUser {
  4. プライベートint id; //主キーID、自己増分
  5. プライベート文字列ユーザーID; //ユーザーIDまたはログイン名
  6. プライベート文字列userName; //ユーザー名
  7. プライベート文字列性別; //性別
  8. プライベートint年齢; //年
  9. //get、 set 、toStringメソッドを省略
  10. }

ステップ5. Daoレイヤーを作成する

通常、データベースを直接処理するコードは、すべてのデータ アクセス ロジックが配置されている DAO レイヤー (データ アクセス オブジェクト) に配置します。

新しい dao パッケージを作成し、その下に新しい **interface** を作成します。これはインターフェースであることに注意してください。

  1. @マッパー
  2. パブリックインターフェースUserDao{
  3. @ Select ( "SELECT id, userId, userName, gender, age FROM USER WHERE id = #{id}" )
  4. 公共 ユーザーqueryUserById(@Param( "id" ) int id);
  5. }

ここでもう少しだけ言わせてください!

技術的な観点から見ると、モデル内の属性はテーブル内のフィールドとは異なる場合があります。たとえば、データベースに [mobilephone] という携帯電話番号フィールドを追加します。

  1. --携帯電話番号フィールドを追加 
  2. 変更 テーブル ユーザー  ADD携帯電話varchar (15);
  3.  
  4. --userid = 1 の携帯電話番号のデータを更新します 
  5. アップデート ユーザー 携帯電話を'13800000000'設定 ここで、 userid = '1'です。

User.java に [telephone] というフィールドを追加します。

[telephone] がデータベース内の [mobilephone] に対応していることはわかっていますが、これら 2 つのフィールドが対応していることを Mybatis に知らせるにはどうすればよいでしょうか。いくつかの方法があります:

01. SQL ステートメントで制御し、異なる名前のフィールドにエイリアスを付与します。

  1. @ Select ( "SELECT id、userId、userName、gender、age、mobilephone (電話) FROM USER WHERE id = #{id}" )
  2. 公共 ユーザーqueryUserTelById(@Param( "id" ) int id);

02. @Results タグを使用して、異なる設定を持つプロパティとフィールドをマップします (同じ名前のものは省略できます)。

  1. @ Select ( "SELECT id、userId、userName、gender、age、mobilephone FROM USER WHERE id = #{id}" )
  2. @結果({
  3. @Result(プロパティ = "電話" = "携帯電話" )
  4. })
  5. 公共 ユーザークエリUserTelById2(@Param( "id" ) int id);

ただし、モデル クラスを記述するときには、属性をテーブル内のフィールドとまったく同じに保つことをお勧めします。これにより、コードの複雑さが軽減されるだけでなく、コードの可読性が大幅に向上し、エラーの可能性も減ります。

質問がある生徒もいるかもしれません。多くのプロジェクトのデータ構造設計はそれほど標準化されていません。たとえば、フィールド名は flag01、flag02 など、非常に奇妙な名前になる場合があります。このようなフィールドがデータベースから照会され、インターフェースを通じて返されると、インターフェースの読みやすさが極端に悪くなるでしょうか?

通常、モデルの内容を直接パッケージ化して返すことはありません。多くのモデルはデータベースと Java オブジェクト間のマッピングであり、通常、データ転送には DTO が必要です。データベースからデータをクエリし、それをモデルに格納します。インターフェイスでデータを返す前に、モデルを DTO に変換し、DTO 内の属性の標準化と意味の明確化を確保する必要があります。

ステップ6. サービス層を作成する

これで、プロジェクトには、データにアクセスするための Dao レイヤーと、ユーザー提供のインターフェース アクセスを提供するためのコントローラー レイヤーが追加されました。では、コントローラーは Dao 内のメソッドを直接呼び出すことができるのでしょうか?直接電話しないほうがいいですよ!

通常、ビジネス ロジックを保存するためにサービス レイヤーを作成します。現時点での完全な呼び出しプロセスは次のとおりです。

コントローラー - サービス - Dao

Service パッケージを作成したら、その中に UserService を作成します。

  1. @サービス
  2. パブリッククラスUserService{
  3. オートワイヤード
  4. ユーザーDao ユーザーDao;
  5.  
  6. 公共 ユーザークエリUserById( int id) {
  7. userDao.queryUserById(id)を返します;
  8. }
  9. }

ステップ7. コントローラー層にインターフェースを追加する

ユーザー ID で顧客情報を照会し、顧客情報を返すインターフェースを追加します。

  1. @RequestMapping(値 = "/queryUser/{id}" )
  2. @レスポンス本文
  3. public String queryUserById(@PathVariable( "id" ) int id){
  4. ユーザー ユーザー= userService.queryUserById(id);
  5. 戻る ユーザー== null ? "ユーザーが見つかりません" : user .toString() ;
  6. }

ステップ8. テストと検証

デバッグやテストのためにブラウザまたはクライアントのインターフェースにアクセスし、顧客情報を照会できます。

  1. http://127.0.0.1:8088/queryUser/1
  2.  
  3. ユーザー[id=1、userId=dashu、userName=uncle、性別=M、年齢=18、電話= null ]

03MyBatisのその他の操作

キーコードのみが提供されます。完全なコードについては、この章のプロジェクト コードを参照してください。

01. 追加

  1. @Insert ( " INSERT INTO USER(userId, userName, gender, age) の値"  
  2. + " (#{userId}, #{userName}, #{gender}, #{age})" )
  3. パブリックvoid insertUser(ユーザー ユーザー);

02. 変更

  1. @更新( "UPDATE USER SET mobilephone = #{telephone} WHERE id = #{id}" )
  2. パブリックvoid updateUserTel(ユーザー ユーザー);

03. 削除

  1. @削除( "ID = #{id} のユーザーから削除" )
  2. パブリックvoid deleteUserById(@Param( "id" ) int id);

4. コードの改善

上記では、Spring Boot と MyBatis の最も単純な統合が完了し、CRUD 用にデータベースを正常に読み取ることができるようになりました。ただし、これは最も単純な統合であるため、次のような改善が必要な詳細がいくつかあります。

パラメータはすべて URL に表示されます。

Object.toString() を直接返しますが、これはあまり使いやすくありません。

データが見つからなかったか例外が発生し、特別な処理は行われませんでした。

少しずつ改善していきましょう

01. JsonをパラメータとしてPostリクエストを送信する

RESTful スタイルに厳密に従う場合は、次の点に従う必要があります。

クエリ: GET /url/xxx

新規: POST /url

変更: PUT /url/xxx

削除: DELETE /url/xxx

ここでは単純に URL にパラメータを記述することでパラメータの内容を一目で確認しやすく、パラメータが増えると URL が長くなりすぎるため、通常は Json をパラメータとして使用して Post リクエストを送信することに慣れています。たとえば、新しいユーザーを追加するためのインターフェースは次のように記述できます。

新しい DTO パッケージを追加し、新しい UserDTO を作成します。

  1. //Josn をパラメータとして使用する場合は、headers = { "content-type=application/json" }を設定する必要があります。
  2. //@RequestBody UserDto userDto はJSON文字列を自動的にバインドしてUserDtoに変換します
  3. @RequestMapping(値 = "/insertUser2" 、ヘッダー = { "content-type=application/json" })
  4. @レスポンス本文
  5. パブリック文字列 insertUser2(@RequestBody UserDto userDto){
  6. //DTO をモデルに変換
  7. ユーザー ユーザー= 新しいユーザー();
  8. ユーザー.setUserId(userDto.getUserId());
  9. ユーザー.setUserName(userDto.getUserName());
  10. ユーザーの性別を設定します。
  11. ユーザー.setAge(userDto.getAge());
  12.  
  13. userService.insertUser(ユーザー);
  14.  
  15. 戻る  "成功" ;
  16. }

ユーザー インターフェイスが追加されました:

  1. //Josn をパラメータとして使用する場合は、headers = { "content-type=application/json" }を設定する必要があります。
  2. //@RequestBody UserDto userDto はJSON文字列を自動的にバインドしてUserDtoに変換します
  3. @RequestMapping(値 = "/insertUser2" 、ヘッダー = { "content-type=application/json" })
  4. @レスポンス本文
  5. パブリック文字列 insertUser2(@RequestBody UserDto userDto){
  6. //DTO をモデルに変換
  7. ユーザー ユーザー= 新しいユーザー();
  8. ユーザー.setUserId(userDto.getUserId());
  9. ユーザー.setUserName(userDto.getUserName());
  10. ユーザーの性別を設定します。
  11. ユーザー.setAge(userDto.getAge());
  12.  
  13. userService.insertUser(ユーザー);
  14.  
  15. 戻る  "成功" ;
  16. }

インターフェースを呼び出してテストしてみましょう:

  1. {
  2. 「ユーザーID」 : 「lisi」
  3. 「ユーザー名」 : 「李思」
  4. 「性別」 : 「F」
  5. 「年齢」 : 「40」
  6. 「電話」 「186000000000」  
  7. }

02. 標準化された戻りパラメータ

Object.toString() を直接返しますが、これはあまり使いやすくありません。

コード (ステータス コード)、メッセージ (例外情報の説明)、データ (データ) を含む単純な戻り参照オブジェクトを設計してみましょう。

  1. パブリッククラスJsonResponse{
  2. プライベート文字列コード;
  3. プライベート文字列メッセージ;
  4. プライベートオブジェクトデータ。
  5. // setメソッドとgetメソッドを省略
  6. }

コードについては、Http ステータス コードを参照し、よく使用されるコードをいくつか使用します。

  1. パブリッククラスResponseCode{
  2. 公共 静的最終文字列 SUCCESS = "200" ; //クエリ成功
  3. 公共 静的最終文字列 SUCCESS_NULL = "204" ; //クエリは成功しましたが、データがありません
  4. 公共 静的最終文字列PARAMETERERROR = "400" ; //パラメータエラー
  5. 公共 静的最終文字列 FAIL = "500" ; //サーバー例外
  6. }

今回は、クエリ インターフェースを書き直してみましょう。

  1. @RequestMapping(値 = "/queryUser2" )
  2. @レスポンス本文
  3. パブリックJsonResponse queryUser2ById(@RequestBody UserDto userDto){
  4. JsonResponse res = 新しい JsonResponse();
  5.  
  6. //パラメータ検証を省略
  7.  
  8. ユーザー ユーザー= userService.queryUserById(userDto.getUserId());
  9.  
  10. if(ユーザー!= null ){
  11. //結果をクエリし、それを戻りパラメータにカプセル化できます
  12. res.setCode(レスポンスコード.SUCCESS);
  13. res.setData(ユーザー);
  14. }それ以外{
  15. //結果が見つからない場合は'204'を返します 
  16. res.setCode(レスポンスコード.SUCCESS_NULL);
  17. res.setMessage( "データが見つかりません" );
  18. }
  19.  
  20. resを返します
  21. }

呼び出し結果には、カプセル化された戻りパラメータが表示されます。これは、はるかに標準化されているようです。

  1. {
  2. 「コード」 : 「200」
  3. "メッセージ" : null
  4. "データ" : {
  5. 「id」 : 3,
  6. 「ユーザーID」 : 「lisi」
  7. 「ユーザー名」 : 「李思」
  8. 「性別」 : 「F」
  9. 「年齢」 : 40,
  10. 「電話」 : null  
  11. }
  12. }

03. 例外処理

コードの実行中に例外が発生した場合、どのように処理すればよいでしょうか?例外情報はフロントエンドに直接返されるべきでしょうか?これは発信者にとってあまり親切ではありません。通常、エラー ログをローカルに出力し、呼び出し元に例外ステータス コードを返します。

サービス層と Dao 層の統合は上向きに行われます。

  1. 公共 ユーザーqueryUserById( int userId) は例外をスローします{
  2. userDao.queryUserById(userId)を返します
  3. }

コントローラー層で例外をキャッチし、戻りパラメータをカプセル化します。

  1. ユーザー ユーザー= 新しいユーザー();
  2. 試す {
  3. ユーザー= userService.queryUserById(userDto.getId());
  4. } キャッチ (例外 e) {
  5. res.setCode(レスポンスコード.FAIL);
  6. res.setMessage( "サービス例外" );
  7. }

4MyBatis よくある質問

01. MyBatis が半自動 ORM フレームワークと呼ばれるのはなぜですか?

半自動もあれば、全自動もあるでしょう。

Hibernate は完全に自動化された ORM フレームワークです。 Hibernate を使用すると、オブジェクトリレーショナル モデルに完全に従って操作できるため、Java オブジェクトを操作するために SQL を記述する必要がなく、完全に自動化されます。一方、MyBatis では、オブジェクトを関連付けるときに SQL ステートメントを手動で記述する必要があるため、「半自動」と呼ばれます。

02. 注釈か XML か?

MyBatis を使用するほとんどのプロジェクトでは、SQL ステートメントを構成するために XML が使用されていますが、このコースの例ではすべてアノテーションが使用されていると思います。では、この2つの違いは何でしょうか?実際の開発ではどのように選択するのでしょうか?

まず、アノテーションを使用して動的 SQL を接合することがより困難であるため、公式には XML を使用することが推奨されています。 SQL がより複雑で、複数のテーブルの関連付けが必要な場合は、XML を使用する方が適切です。そして現在では、MyBatis XML を自動的に生成できるプラグインが数多く存在します。

しかし、コインには常に表と裏がある。複雑な SQL は誇るべきものではありません。複雑な SQL を使用せずにプロジェクトを実行できる場合は、アノテーションを使用する方が適しています (現在のプロジェクトの SQL の 95% 以上は単一テーブル クエリです)。

03. #{} と ${} の違いは何ですか?

${} は文字列の置換、#{} はコンパイル前の処理です。 #{} を使用すると、SQL インジェクションを防ぎ、システムのセキュリティを向上できます。

04. バッチ挿入を行うにはどうすればいいですか?

アノテーション メソッドでは動的 SQL も使用できます。

  1. @入れる {
  2. 「<スクリプト>」  
  3. + "INSERT INTO USER(userId, userName, gender, age) 値"  
  4. + "<foreach コレクション='userList' 項目='item' インデックス='index' セパレーター=','>"  
  5. + " (#{item.userId}, #{item.userName}, #{item.gender}, #{item.age})"  
  6. + "</foreach>"  
  7. + "</script>"  
  8. })
  9. パブリックvoid insertUserList(@Param(value= "userList" ) List< User > userList);

Spring Boot は MyBatis を統合して、データベースの追加、削除、クエリ、および変更操作を実行します。これは比較的基本的な知識であり、Java を初めて使用する人にとって役立つことを願っています。

<<:  JVMはオブジェクトが死んだと判断し、GCリサイクルを検証します。

>>:  2021 年に、エッジ コンピューティングという収益性の高いビジネスを発見したのは誰でしょうか?

推薦する

hostgator - 全製品/共有ホスティング/VPS/専用サーバーが最大75%オフ

HostGator(市場で最も有名な仮想ホスティング ブランドの 1 つで、かつては最高の外国貿易ウ...

ハイブリッド マルチクラウドがクラウドへの正しい道である理由は何ですか?

一般的に、企業はプライベート クラウドまたはデータ センターでアプリケーションを実行し、コンピューテ...

充填機業界におけるSEOの現状とSEOの実施方法

私は半年以上充填機業界に従事しており、いくつかの充填機ウェブサイトを担当しています。充填機ウェブサイ...

皆様にとって幸せな新年とご多幸をお祈りいたします。

今年は、Zhujimao.com が皆様と共に祝う 12 回目の元旦/新年です。皆様が元気いっぱい、...

electricbyte-年間14ドル/256Mメモリ/5Gハードディスク/500G/データ/Gポート/サンノゼ

Electricbyte は、Minecraft サーバー プロバイダーとしてスタートし、現在は V...

成都にチェックインして新しいクラウドコンピューティングのスキルを習得しましょう

ますます多くの企業がビジネスとデータをクラウドに移行することを選択するにつれて、クラウド コンピュー...

Vipshopの血なまぐさいIPOは冷ややかな反応に見舞われた。電子商取引は依然として資本の冬に立ち向かう必要がある

トレイシーブランドディスカウントB2C企業Vipshopは、発行価格が23%引き下げられ、6.5ドル...

hostdoc: 1Tbps の高セキュリティ VPS、無制限のトラフィック、年間 20 ポンドから、シンガポール/フランスに 8 つのデータセンター

Hostdocは2003年に設立されました。主な事業はVPSで、仮想ホスティング、ドメイン名なども提...

専用マインド - 7ドル/4コア/2IP/2gメモリ/100gハードディスク/2Tトラフィック

ヘンズは、Intel Xeon E5620 クアッドコア CPU、最低 64G のメモリ、RAID1...

SEOの詳細が重みを決定し、重みがランキングを決定する

前回の記事「オリジナル記事が転載記事よりランクが低い理由:重量増加」では、Webサイトの重量増加の概...

モバイルインターネット市場でアプリから収益を上げることの難しさについての簡単な分析

2013年5月16日、AppleはApp Storeのダウンロード数が500億回を超え、開発者が70...

Douno ブログ: 正確なトラフィックを獲得する方法

オンラインマーケティングの過程でよく言及されるのは、正確なトラフィックです。正確なトラフィックがオン...

servercheap: 月額 2 ドル、無制限トラフィック VPS、KVM/1G メモリ/1 コア/30g SSD/シカゴ、ロサンゼルス

2009年から運営しているアメリカのVPS業者servercheapが、シカゴデータセンター(cor...

#プレゼントドメイン名: gandi-15周年/ドメイン名各種/プレゼント各種/お金に困らない

福祉は無料で提供されています: gandi.net は 15 周年を迎えました。裕福な人として、私た...