Java Advanced - MyBatis Query Database && Spring Boot Unit Test - 詳細クレイジー

記事ディレクトリ

序文

前回の学習でSpringシリーズの基本的な操作はほぼ実現できたので、次はもっと重要な知識を学び、フロントエンドから渡されたデータを格納したり、データベースにデータをクエリしたりしてみましょう。


1.MyBatisとは?

MyBatisは、カスタム SQL、ストアド プロシージャ、高度なマッピングをサポートする優れた永続レイヤー フレームワークです。MyBatis は、ほぼすべての JDBC コードと、パラメーターを設定して結果セットを取得する作業を取り除きます。MyBatis は、単純な XML または注釈を使用して、プリミティブ型、インターフェイス、および Java POJO (Plain Old Java Objects、Plain Old Java Objects) を構成し、データベース内のレコードにマップできます。簡単に言えば、MyBatis は、プログラムとデータベース間の対話を完了するためのより単純なツール、つまり、データベースを操作して読み取るためのより単純なツールです。Mybatis の公式 Web サイトでは、 MyBatisを優れた永続化レイヤー フレームワークとして分析および補足しています。





MyBatis も ORM フレームワークです。
ORM (オブジェクト リレーショナル マッピング)、つまりオブジェクト リレーショナル マッピング。
オブジェクト指向プログラミング言語では、リレーショナル データベース内のデータとオブジェクトはマッピング関係で確立され、データとオブジェクト間の相互変換が自動的に完了します。
1. 入力データ (つまり、入力オブジェクト) + SQL はネイティブ SQL にマップされます
2. 結果セットを返されたオブジェクトにマップします。つまり、出力オブジェクト

ORM はデータベースをオブジェクトにマップします:
データベース テーブル (テーブル) >>> クラス (クラス)
レコード (レコード、行データ) ) >>> オブジェクト (オブジェクト)
フィールド (フィールド) >>> オブジェクト属性 (属性)
一般的な ORM フレームワークは、データベース モデルの各テーブルを Java クラスにマップします。
つまりMyBatisを使えば、オブジェクトを操作するようにデータベース内のテーブルを操作したり、オブジェクトとデータベースのテーブルとの変換を実現したりできます。

つまり、MyBatis は「ブリッジ」と呼ぶことができます。
その機能は、データベースとプログラムをマップすることです。
マッピング後、一連の操作を実行できます。
例:
query は、データベースとプログラムをマップするため、データ テーブル全体をクラスに直接マップします。
クエリの結果は、クラスのオブジェクト (挿入されたレコードの行) を格納するコレクションであり、データもクエリされます。

データベースとプログラムをマップし、テーブルのデータをオブジェクトに取得しました。次に、オブジェクトのメソッドを呼び出すときに、オブジェクトのメンバーを直接 MySQL に直接保存できます!

MySQL と MyBatis は異なります。
MySQL は、データ アクセス (データ管理) ソフトウェアを提供します。
MyBatis は、プログラムとデータベースを接続し、リレーショナル マッピングを確立し、中間層 (永続層) でデータ操作を実行するために使用される「中間ブリッジ」です。

一般に:
MyBatis の定義: MyBatis は、優れた ORM (オブジェクト リレーショナル マッピング) 永続層フレームワークです。
その役割: プログラムとデータベース間のデータ相互作用を実現します。

PS:
ORM フレームワークは MyBatis だけではありません!
ただ、MyBatis は中国市場の 90% 以上を占めており、中国で幅広い標準的な接着剤を使用しています。
海外で最も使われているのは Hibernate です。

理由としてはMyBatisとHibernateの違いなど。. .
Hibernate を含め、別の Spring JPA がありますが、違いはありますか?
MyBatisが完成したらお知らせします。
(前提は、私​​がまだ覚えているということです、あなたがそれを書かなければ、あなたはそれを自分でBaiduにすることができます)

MyBatis はカスタム SQLをサポートしています

幅広い範囲を含むカスタム SQL。
データベースの「CURD」ステートメントを実装できます。
カスタム SQL の場合、書きたい SQL は何でも記述できます。
このことから、MyBatis の最大の特徴の 1 つである柔軟性を理解することは難しくありません。
これもMyBatisが中国で人気の大きな理由です!! !

その背後にある理由は、国内ユーザーのニーズが本当に奇妙で不均一だからです! !

人生の例を見てみましょう。
ほとんどすべての大学にはコンピューター専攻があります。
しかし!インターネット製品を専攻している学校は? いいえ!! !
大学は教えておらず、外部のトレーニングクラスはほとんどありません。
それらのほとんどは、大学院入試のためのトレーニングコースであり、その後にコンピュータートレーニングが続きます。
コンピュータの開発はまだ比較的成熟しています。
しかし!プロダクトマネージャーとプロダクトのトレーニングについては、基本的にはこのトレーニングを行う機関です。
とにかく見たことがない。
その理由は、シェアが高くなく、関心の兆しが見えないからです。
当然、それは人々に対してこれを行いません。
このように言いましょう: 一部の企業では、プロダクト マネージャー、つまりポジションが存在しません。

したがって、将来私たちが出会うほとんどのプロダクト マネージャーは、口だけでニーズを尋ねますが、この要求が実現するのがどれほど複雑かはわかりません。
トレーニングがなく、現在のプロダクト マネージャーのほとんどがテクノロジーを理解していない
ため、彼らの要求はあらゆる種類の奇妙なものになっています。
そのため、完全にでたらめな電話ケースについてのジョークがあります。
1 つのソフトウェア、1 つのハードウェア、2 つの絶対に勝てないもの。

したがって、MyBatis の柔軟性の役割が反映されます。
様々なニーズに応えるだけ。

外国では、技術と製品が合理化され、訓練されています。
やはり外国はコンピュータの発祥地であり、急速に発展していることは容易に理解できます。
展開が激しく、安定しています。

ストアド プロシージャ

以前使っていたSQLは、Dormaの複雑なSQLでも1行のSQLで解けます。
SQLではforループやif判定など特に複雑な業務はありませんから。. . どれでもない。
これは、通常の SQL 用の非常にスムーズな 1 次元 SQL 操作です。

しかし!ストアド プロシージャは、多くの SQL で構成される SQL のメソッドです。
この構成では、ループ、判定、分岐、および可変伝送があります。
これをストアド プロシージャ、つまり SQL のメソッドと呼びます。
逆に言えば
、SQLメソッドの処理によって生成されるものをストアドプロシージャと呼びます。

後で、私たちが仕事をした後、SQL ステートメントがぎっしり詰まったストアド プロシージャが他の人から渡されます。
if 判定、for ループ、変数の値の設定もあります。
そして、入力パラメーター、出力パラメーター、とにかく SQL ステートメントの長い文字列です。
数十行から数千行。

では、なぜ私たちプログラマーはこのストアド プロシージャを使用しないのでしょうか。
これは、実際にはストアド プロシージャの特性に関連しています。
ストアド プロシージャは複雑なビジネスを実現できますが、しかし! これは、ビジネスをプログラム側から SQL 側に移すだけです。
この場合、プログラマーに対する会社の要件は非常に高くなります。! !

想像してみてください。会社が数百行の SQL ステートメントであるストアド プロシージャを提供したので、おそらく目をつぶったことでしょう。
理解できれば、幽霊がいます。. .

しかし、それは誰かがやらなければならない、特別な専門DBAの誕生です。
DBA: データベース管理者 - データベース管理者。データベース開発エンジニアとも呼ばれます。
彼の SQL は非常に優れており、プログラムを作成する必要はありません。
毎日、SQL ステートメントをいじり、データベースだけをいじり、データをいじっています。

ほとんどのプログラマーは、ストアド プロシージャをまったく理解していません。これは非常に複雑なことです。
また、ストアド プロシージャには非常に使いにくいものがあります。
非常に複雑な Java コードを入力しているときは、デバッグを段階的にデバッグし、クラス、メソッド、およびプロパティを入力してランタイム ステータスを観察できます。これは、プログラムのエラーのトラブルシューティングに役立ちます。また、プログラムをデバッグすることもできます。

ただし、ストアド プロシージャはデバッグできません。
つまり、数百行の SQL ステートメントを含むストアド プロシージャを作成する必要があります。
また、誤差があり、誤差は肉眼でしか確認できません。[デバッグはサポートされていません]
あえて言えば、プログラマーの 90% はこれができません。
これは真の天才にしかできない仕事です。

しかし!心配しないでください!
会社が私たちプログラマーにこれをさせることも不可能です。
通常、外部の専門家によって実行されます。
ストアド プロシージャは、病院で最も一般的に使用されます。
病院は、毎日、毎月、毎年、データ (収入、出席など) を集計 (さまざまなレポート) する必要があります。
要するに、多くのデータが関係しています。
これには、さまざまなデータ テーブルからデータを抽出する必要があります。
この時点では、単純な SQL ステートメントは機能しません。
このとき、ストアド プロシージャが使用されます。

ストアド プロシージャの難しさから、非常に大きいです。
人々への要求は非常に高く、それに伴って高賃金が発生します。
おそらく、プログラマーの給与の 1.5 倍以上です。
つまり、10,000元の給与に同意するプログラマーを募集し、DBAの給与は少なくとも1w5以上である必要があります。そうしないと、誰も見つけることができません。

高度なマッピング

高度なマッピングは、プログラム内のデータ テーブルとオブジェクトのマッピングに加えて、1 対 1 のマルチ テーブル マッピングと 1 対多のマッピングを実現できます。

例: CSDN の
すべてのブログ投稿には、その作成者がいます。
ブログ投稿と著者の関係は 1 対 1 の関係です。
この時点で、MyBatis を使用して、クエリ時にテーブル クエリを実行し、クエリされたデータの結果を記事オブジェクトの 1 つにマップできます。

繰り返しになりますが、著者である彼は、多くのブログ投稿を公開できます。
この観点から、著者は自分が発行するブログ投稿と 1 対多の関係を持っています。
この場合、MyBatis を使用すると、このタスクも達成できます。
MyBatis は、データベース内のデータを直接クエリし、そのデータを UserInfo に割り当てることができます。
この UserInfo は属性 (リスト記事 - 記事リスト) を持っています。
作者が制作した作品を記録するために使用されます。

MyBatis は、ほぼすべてのJDBC コードと、パラメーターを設定して結果セットを取得する作業を取り除きます。

以前は、JDBC プログラミングを行っていたときに、データ ソース オブジェクト (DataSource) を取得し、URL (データ ソース パス)、ユーザー名 (デフォルトは root)、パスワード (MySQL ログイン パスワード) の 3 つの属性を設定する必要がありました。
この 3 つの項目を設定すると、データに接続して一連の操作を実行できます。

さらに、結果セットを取得する場合、クラスのオブジェクト (ResultSet) を使用してデータベースから返された結果セットを受け取る必要があり、イテレータを使用して後続の出力を実行する必要があります。

MyBatisなら、靴を履く必要はありません。
マッピングを認識するのに自動的に役立ち
ます。SQL ステートメントを記述するだけで済みます (間違って記述しないでください)。記述後、SQL ステートメントを実行し、すべてのクエリ結果 (テーブル データ) をオブジェクトに直接マップします。
つまり、JDBC の事前操作のためにコードを 1 行も書く必要はありません。
MyBatis は直接オールインクルーシブで、直接使用できます。
とてもかっこいい!

MyBatis は、単純な XML または注釈を使用して、プリミティブ型、インターフェイス、および Java POJO (Plain Old Java Objects、Plain Old Java Objects) を構成し、データベース内のレコードにマップできます。

MyBatis を実装する場合、次の 2 つの実装方法があります
。 1. xml を介してデータ操作を実装し、データ操作はすべての型をサポートします。
MyBatis version 3.1以前は主流の操作方法でした。
xml の形式を使用して、データベースに「CURD」操作を実装します。

しかし!バージョン 3.1 以降、MyBatis には新しいオプションがあります。
それが2つ目の方法(アノテーション方法)です。
しかし、現在の主流は依然として xml 形式を使用しています。
なぜ?
MyBatis が非常に柔軟に使用できるとは言いません!
柔軟性には代償が伴います。
その代償は、SQL ステートメントを作成する必要があることです。
考えてみてください: アノテーションに SQL ステートメントを書くのは面倒ですか?
多くのコードはありませんが、コメントは非常に長いです。
そのため、バージョン 3.1 以降の MyBatis では、アノテーションによってデータを操作する新しい方法が提供されています。
それもうまくいかないからうまくいかない。
注釈メソッドを使用して、単純な SQL 操作を実装することは引き続き可能です。
しかし!SQL ステートメントがもう少し複雑になると、使用するときに特に扱いにくくなります。
コメントはコードよりも長くなります。. .
また、xml はより柔軟に SQL ステートメントを記述できるため、扱いにくく、使いやすくなっています。

したがって、この記事も xml に基づいてデータベースの操作を実現します。


MyBatisを学ぶ理由

バックエンド開発の場合、プログラムは次の 2 つの重要な部分で構成されます

1. バックエンド プログラム
2. データベース
ここに画像の説明を挿入

これら 2 つの重要なコンポーネントが通信するには、データベース接続ツールに依存する必要があります。
例えば、以前に学んだJDBCや、今日紹介する MyBatis にはすでに JDBC があるのに、なぜ MyBatis を学ぶ必要があるのでしょうか。

これはJDBCの操作が煩雑すぎるためです. JDBCの操作プロセスをおさらいしましょう:
1. データベース接続プールのDataSourceを作成する
2. DataSourceを介してデータベース接続 Connection を取得する
3. 実行するSQL文を?プレースホルダで記述する
4 . . Connection と SQL を使用して操作コマンド オブジェクト Statement を作成する
5. プレースホルダーを置換する: 置換するデータベース フィールド タイプ、プレースホルダー インデックス、および置換する値を指定する
6. Statement を使用して SQL ステートメントを実行する
7. クエリ操作: 結果セットを返す ResultSet、更新する操作: 更新の数を返す
8、結果セットを処理する
9、リソースを解放する
コード例 - 挿入操作 - 自分の記事のコンテンツをインターセプトします。
ここに画像の説明を挿入
上記のコードと操作プロセスからわかるように、JDBC の場合、操作全体が非常に面倒です. 各パラメーターを接合するだけでなく、テンプレートコードに従ってデータベースを段階的に操作する必要があります. 各操作の後,手動で接続を閉じるなど、これらすべての操作手順を各方法で繰り返す必要があります。そこで、もっと簡単で便利な方法でデータベースを操作する方法はないかと考えました。
答えはイエスです。これが MyBatis を学びたい本当の理由です。MyBatis は、データベースをより便利に、より速く操作するのに役立ちます。
jdbc を使用する前は、9 つ​​の手順が必要でしたが、MyBatis を使用すると、メソッドを記述するだけで SQL が実行されます。手動でリソースを解放して結果セットを処理するのと同じように、もうそれを行う必要はありません。MyBatis の「乳母レベル」のアシスタント。


MyBatisを学ぶには?

この記事の焦点は 2 つの部分に分かれてい
ます。 1. MyBatis 開発環境を構成する (SSM プロジェクトを作成する)
2. MyBatis スキーマと構文を使用してデータベースを操作する


1.MyBatis プロジェクトを作成する

準備: データベースとデータ テーブルの作成

次に、ブログに関するデータベース mycnblog を
作成し、mycnblog データベースに 3 つのテーブルを作成します。
これがあなたのためのコードです、Dai! その中には「殺人」が隠されている。
それはバグにつながります。それ以外の場合は解決策があり
ます。最初に実行してください。

しかし、注意すべき点が 1 つあります。
article テーブルのコンテンツ フィールドでは、その型はテキストです。
text は限られたテキスト コンテンツを表すことができますが、実際には、通常は longtext が使用されます。
また、createtime フィールドには now メソッドを使用しますが、この now メソッドには MySQL のバージョンが 5.5 以上である必要があります。
しかし、それは大きな問題ではないはずです.結局のところ、jdk1.8 で使用するデータベースのバージョンはバージョン 5.7 です。

以下の SQL の作成を注意深く見てください.データベースまたはデータ テーブルのどちらを作成する場合でも、文字セットを utf8 に設定しています。
中国語に対応していることを確認してください。
これの利点は、データベースの構成を変更しなくても、作成されたテーブルが引き続き中国語をサポートすることです。

もう 1 つ細かい点: ユーザー情報を追加する SQL ステートメントでは、パスワードはクリア テキストで保存されます。
このように書くと、間違いなく面接官から批判されます。
暗号化に md5 を使用しても、実際にはあまり効果がありません。
それが単なる md5 の場合、実際に「虹のテーブル」を使用してパスワードを徹底的に取得できます。(注意! これは復号化ではなく、パスワードを列挙する可能性です)
誰かが考えることができます:
1 つの md5 の場合、レインボー テーブルを介してパスワードを徹底的に取得できます。
では、パスワード md5 を 2 回、またはそれ以上使用するのはどうでしょうか。
虹のテーブルは壊れますか??
あなたは思いつきますが、他のハッカーは思いつきませんか??
2 回言わないでください。たとえ 3 回、4 回、または 5 回実行しても、人々はそれに対処します。
また、md5 で暗号化を何度行っても、実際には累積的な効果であり、ハッカーにとっては、数回の試行錯誤にすぎません。
最も信頼できる方法は、乱数と変数を使用することです。
これでさらに安心!
ランダム生成なのでルールは一切なし!
パスワードを取得するのは非常に困難です!
ほぼ不可能である。

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8;
-- 使⽤数据数据
use mycnblog;
-- 创建表[⽤户表]
drop table if exists userinfo;
create table userinfo(
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime datetime default now(),
updatetime datetime default now(),
`state` int default 1
);
-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime datetime default now(),
updatetime datetime default now(),
uid int not null,
rcount int not null default 1,
`state` int default 1
);
-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
vid int primary key,
`title` varchar(250),
`url` varchar(1000),
createtime datetime default now(),
updatetime datetime default now(),
uid int
);
-- 添加⼀个⽤户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`,
`createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48',
1);
-- ⽂章添加测试数据
insert into articleinfo(title,content,uid)
values('Java','Java正⽂',1);
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java
title','http://www.baidu.com',1);

ローカルの MySQL を開き、上記の SQL をコピーして MySQL に貼り付けます。
PS: 最初にテキスト ファイルにコピーしてから、MySQL にコピーすることをお勧めします。
上記の内容をそのままコピペするとSQLが山積みになってしまうからです。
つまり、フォーマットなしです。
ここに画像の説明を挿入
最初に上記のコードをノートブックに配置してから、MySQL に貼り付けます。
それらが密集していないだけでなく、すべての SQL が実行され、最後の SQL 文だけが実行されません。
戻るだけで、すべて問題ありません。
ここに画像の説明を挿入
データが正常に挿入されたかどうか見てみましょう
ここに画像の説明を挿入


1.1. MyBatis 関連の依存関係を追加する

目の肥えた友人は、私が「適切な」という形容詞を使用していることに気付くでしょう。
はい、MyBatis を使用したい場合、MyBatis の依存関係を導入するだけでは十分ではありません。
(データベースへの) 依存関係を導入する必要があります。

ここでは 2 つのシナリオが関係します。
1. プロジェクトの作成時に、MyBatis 関連の依存関係を導入します
。 2. 古いプロジェクトの場合、MyBatis を追加します。


1. 新しい MyBatis プロジェクトを作成する


ここに画像の説明を挿入
ここに画像の説明を挿入
次に、不要なファイルを削除します。
ここに画像の説明を挿入


2. MyBatis 関連の依存関係を古いプロジェクトに導入する

これは何度も言われており、Edit Starter プラグインを使用して追加されています。
ここに画像の説明を挿入


1.2、データベース接続文字列を構成する

不要立即启动项目!!!!
如果立即启动项目,就会报错。
指针对 社区版 idea,专业版会帮助我们自动生成关于 数据库的 配置信息。

社区版:
这是因为 没有配置 关于 数据库的数据源的 URL
ここに画像の説明を挿入

专业版:
直接就给我们配置好了。
ここに画像の説明を挿入

现在我把的配置文件删除掉,重新创建一个配置文件,与社区版保持一致,我们来重新编写配置信息。

我们需要配置 4 项:
ここに画像の説明を挿入
此时,我们再启动项目,就不会报错了。
ここに画像の説明を挿入


1.3、配置 MyBatis 保存的 xml 的目录

我们前面说过 MyBatis 有两种 操作方法:
1、使用 xml 的形式 实现呢
2、 注解(MyBatis 3.1版本之后,开始提供)
但是!
注解的方式,并不好用。
因此,我们主要还是关注 xml 形式,是如何操作 数据库。

思考一下:
xml 是一个 资源文件,对不对?
那么,xml 文件,还是放在 resource 目录下。
还有一个问题:
放在 resource 哪个 目录底下。

需要注意的是:一般是不会将其放在 resource 根目录底下,与配置文件处于同一级目录。
因为到时候,配置文件,非常多!
此时,你放进去,不就是添乱嘛!!!

通常我们都是在resource 目录下,创建一个子目录,用来存放的。
ここに画像の説明を挿入


使用 MyBatis 的操作模式 操作数据库

MyBatis 的操作模式

ここに画像の説明を挿入

MyBatis 的 操作模式,包含两个部分:
1、Interface(方法定义)
2、xxx.xml

注意!这里是接口,不是类。
这个interface 中 会加一个注解,它是来自于mybatis里面的注解 Mapper。
加了这个注解之后,表示我们当前的这个 mybatis 类 所的事情,就是 实现 对象的映射。
这个时候,帮我们的方法名字 定义到 interface 里面。
我们 interface 里面的方法,是不能有实现的,是一个抽象方法。

思考一下:
假设,我们要根据用户ID 去查询一个用户信息。
那我们定义一个方法名有什么用?又没有具体实现,怎么可能会实现查询功能??
答案显而易见是不行的!!!
'这个时候,我们就需要另一个东西:xml 文件
mybatis 有点奇怪,感觉就像是 “怕脑门” 想出来的方法 。
就是 要想操作数据库,必须得有两个文件。
第一个,它是Java中的 一个普通接口,在接口中,定义方法名称。
定义方法名称之后,就该实现方法了。
但是接口中方法不能有实体,需要通过一个注解来进行映射方法,映射一个 xml 文件中。
当然,在xml文件中,也需要表明它是那个方法的映射。
这就是第二个文件 xml。
根据我们前面讲的映射:就是 把业务代码 转换成 SQL 语句。
也就是说我们 定义在接口中的方法,是为了声明该方法 对数据 进行 何种操作。
具体的实现 已经通过某种映射关系,映射到 xml 文件中,
我们需要在 xml 文件中,编写 对应功能的 SQL 语句,就可以了。

有的人可能会疑问:
我们可不可以将 SQL 语句 写在代码中,就像 jdbc 编程 一样。
答案:可以,但是!SQL 只能是 String 类型的,如果SQL写错,它是不会报错的。
这就很容易翻车。
所以,mybatis 的设计师 思考一会,这样的话要不直接把 SQL 写在 xml 里面?
于是一拍大腿,就这么决定了。
在xml里面,只需要配置 我们要是实现的 interface 是谁,我要实现的 SQL 是谁。
OK ,这样一配置就完了。
这两个合在一起,最终生成 mybatis 中能执行的SQL。
通过这个SQL语句,去操作数据库。
将 操作数据库得到的结果,返回给 服务层。
服务层,再返回给 controller(控制层)。
控制层,再把结果交给用户。
这样 就完成了 一次交互。

所以,我们讲 mybatis 的 操作模式,就是在讲下图中的两个文件。
ここに画像の説明を挿入
这两个配合起来,就能生成 数据库可以执行的SQL语句,并且执行 SQL,操作数据库。
并将 结果 映射到程序的对象中。


第⼀个MyBatis查询:实现一个根据用户id来查询用户信息的操作

我们要实现一个 根据 用户id 来查询用户信息的操作。
前面我们在准备工作中,就是已经给 userinfo 表中插入了一个数据。
ここに画像の説明を挿入
下面,我们就来完成这样的一个功能。


1、定义接口

ここに画像の説明を挿入


2、创建 xml,实现上面的接口

xml 文件,不能随便创建。
我们在配置文件中,已经指定了 xml 文件存储路径。
并且,命名规则也指定了。
ここに画像の説明を挿入
我们必须按照规则来。
ここに画像の説明を挿入
至于 xml 文件的配置内容,直接把下面的内容,拷贝到里面去。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
</mapper>

相信很多朋友,都会发现 mapper标签中的 namespace 属性,缺少value值。
ここに画像の説明を挿入
namespace 的值,是需要我们手动去填写的。
填写的内容:是需要时实现的接口位置 >> 包名 + 接口名称。
ここに画像の説明を挿入
接下来,就是在 xml 文件中,实现 UserInfoMapper 接口 中的 方法。
ここに画像の説明を挿入
关于获取方法参数,使用的 ${} 和 #{} 的区别,后面会详细讲。
&enso;
好,关于 MyBatis 的操作,就都完成了。
下面,我们就可以来验收成果了。


运行结果展示

我们在 service 包底下创建一个 UserInfoService 类。
在里面 写一个方法, 去 调用 UserInfoMapper 中的方法。
然后,在 controller 包下,也去创建这样的一个类,去调用 UserInfoService 中的方法。
ここに画像の説明を挿入
此时,我们将项目启动起来。
ここに画像の説明を挿入


注意!有的人可能会在这一步出现问题

ここに画像の説明を挿入

我被坑的头皮发麻。
第一次遇见版本不匹配,引起的错误。
看异常信息检查不出错误。
出现这个问题的原因是:我们添加的 MyBatis r的版本太高了,而我们使用的 Spring Boot 版本太低了(阿里云提供的)。导致的版本不兼容。
因此 URL 不能像正常情况下,那样去配置。
ここに画像の説明を挿入
应该这样去配置
ここに画像の説明を挿入
更简单解决方法的是:使用官方 提供的Spring Boot 框架,选择次新的。
ここに画像の説明を挿入
我使用的是 阿里云,所以 版本很低,我是用的版本是 2.3.7。
所以,才会出现上述情况。


MyBatis 执行过程

ここに画像の説明を挿入

在这里,我在补充一点。
我们在写 mybatis 代码的时候,无非就是两个操作:1、创建接口,定义方法;2、在写满了文件中编写SQL。
整个 mybatis 操作 完成了。

这里有一个比较麻烦的地方:
就是在我们写完功能之后,我们要进行测试的话,成本很高!

mapper的内容写完,我们还需要写 service,写 controller,还没完!
我们还需要打开 浏览器方法(或者利用postman来模拟访问)。
虽然整个流程,非常有序,一环接一环。
但是!这会让人感觉很拖!
给人的感觉就是:代码被强行 “ 拉长 ” 了。

那有没有什么方法,能让我们写 mapper 内容之后,直接可以进行测试呢?
这就是下面,我要讲的东西:Spring Boot的单元测试


Spring Boot的单元测试 - 穿插内容

讲这个,是为了后面讲解 Mybatis 的内容。

1.什么是单元测试?

单元测试(unit testing),是指对软件(项目)中的最⼩可测试单元进⾏检查和验证的过程就叫单元测试。

单元测试是开发者编写的⼀⼩段代码,⽤于检验被测代码的⼀个很⼩的、很明确的(代码)功能是否正确。
执⾏单元测试就是为了证明某段代码的执⾏结果是否符合我们的预期。如果测试结果符合我们的预期,称之为测试通过,否则就是测试未通过(或者叫测试失败)。

最小可测试单元:方法
每一个方法都代表一个相应的功能。
那我们测试的最小单元,对于 Spring Boot 来说,就是一个方法。
OK,你写一个方法,我测一个方法。
测试方法,就是测试一个单元。
方法,是不可以再被分割的!
你不可能说: 我们去测试 方法中的某一段程序,或者说测试某一个属性。
因为,这叫做 调试。
调试 和 测试单元,是两码事!!!!

但是!有的朋友可能会说:
方法中,经常会调用另一个方法,来“辅助”自身的运行。
那这种怎么说?
如果方法中还有方法,这个时候,单元测试就需要分为多个了。
首先是这个方法中所有依赖的方法,我们可以对这里面所有的方法,做一个单元测试。
最后,再回到本身,对本身的方法进行单元测试。


2、单元测试有哪些好处?

1、单元测试不用启动 Tomcat

对于这一点,不好说。这个说法,要分角度来看。
从自身的角度来看:我们确实没有启动 Tomcat,但是 Spring Boot 自动启动了 Tomcat。
因为 Spring Boot 内置了 Tomcat。
其实 Spring Boot 除了支持 Tomcat,还支持其它的Web容器。

2、如果中途修改了代码,在项目打包的时候会发现错误,因为打包的时候会自动执行单元测试,单元测试错误就会发现。
这一点最重要!
ここに画像の説明を挿入
3、单元测试,最大的一个好处 :
让我们非常方便,非常直观,也非常直接的,在写完一个功能之后,立马就能知道这个功能是否是正确的!
这也是我们学习单元测试的初衷,就是为了降低 测试 mybatis 功能的成本。

4、不使用单元测试的时候,它是会 “ 污染 ” 本地的数据库的!
就是比如说:
我们实现了一个 添加 功能,我们要去测这个添加功能。
这就需要正儿八经的去进行添加操作的。
这就会对本地数据库中的数据,发送变动。
这就是 “污染”!

然而,如果使用了 单元测试 来测试功能,.
测试单元,就能保证在 测试完功能之后,对于数据库中的数据没有任何影响!

这个牵扯到了 事务的回滚机制。
这是 我在讲 MySQL是如何保证事务的原子性 的 时候,提到过的 事务回滚机制。
有兴趣,就自己去看,目录给你标出来了。
ここに画像の説明を挿入
单元测试,也是通过利用 数据库的回滚机制 来 避免对 数据产生 “ 污染 ” 。
也就是说:我们在执行单元测试之前,MySql 为其创建了一个事务。
【MySQL 默认情况下,是处于开启事务的状态,也就说开启了事务的自动提交】
然后,开始执行单元测试,对数据库中的数据进行操作。
在验证完 单元的功能没有问题之后,就会进行事务的回滚操作。
还原到 还没有测试的情况。【将数据还原到初始状态】


3.Spring Boot 单元测试使用

Spring Boot 项⽬创建时会默认单元测试框架 spring-boot-starter-test,⽽这个单元测试框架主要是依靠另⼀个著名的测试框架 JUnit 实现的,打开 pom.xml 就可以看到,以下信息是 Spring Boot 项⽬创建是⾃动添加的:
PS:我用来演示效果的项目,是我一步一步带着大家创建的。
所以,作假含量极低。我可没有偷偷添加这个依赖!
都是 Spring Boot 干的!!!雨我无瓜!
ここに画像の説明を挿入
这里有一个细节:
ここに画像の説明を挿入


&enspp;

单元测试的实现步骤

1.⽣成单元测试类

ここに画像の説明を挿入

这个时候,此⽅法是不能调⽤到任何单元测试的⽅法的.
此类只⽣成了单元测试的框架类,具体的业务代码要⾃⼰填充。


2 添加单元测试代码

1.添加 Spring Boot 框架测试注解:@SpringBootTest

至于为什么还需要加一个 测试注解,是因为 我们生成测试类,是一个普通的类。
ここに画像の説明を挿入
但是!测试接口,它是一个普通的接口吗?
ここに画像の説明を挿入
因此,我们需要在测试类上 声明它要测试的方法,是运行在 Spring Boot 容器当中的。
所以,@SpringBootTest 注解,就是起着这样的一个声明作用。
表示当前这个类中 测试方法(测试单元) 是运行在 Spring Boot 中的。
ここに画像の説明を挿入


2.添加单元测试业务逻辑

ここに画像の説明を挿入


3、开启测试

ここに画像の説明を挿入

虽然,从打印的结果来看,功能是没有的。
而且,左边那几个 绿色勾勾,代表测试通过。
ここに画像の説明を挿入
但是! 我们是使用 的 sout 语句,来对查询结果进行输出。
这并不是 我们 单元测试的效果!!!!
单元测试的效果应该是 单元测试中的断言!!!

断言:
就是说:以什么为标准,
通过这个标准来衡量 测试是否通过。
比如,如果 断言的结果为 true,就表示 单元测试 通过了。
反之,断言的结果为 false,就表示 单元测试 不通过。
并且!断言之后的代码,是不再执行的!!!

所以。还没有完。
单元测试,还有一部分是关于 断言 的 内容。
我们是需要知道的。


4、简单的断⾔说明

由 Assertions 类提供的,注意!这个类是 JUnit 提供的
ここに画像の説明を挿入
下面,来跟着我看一下,如何使用断言,来判断单元测试是否通过!
ここに画像の説明を挿入
这就是断言的魅力,一旦出错。
如果测试失败,它的报错信息会非常非常的详细!

后面,我们实现 增,删,该2的时候,就不需要 浏览器 和 postman了。
直接使用断言,来测试即可。

这里做一个小拓展:
为什么有些人的 科学版 idea, 在进行 与 @Mapper 相关的属性注入,使用 @Autowired 来注入,为什么会报错?
ここに画像の説明を挿入


拓展:“小鸟” - 插件 MyBatisX

它能够帮助我们快速切换 接口 和 xml。
让我们操作 MyBatus 更舒服。
而且,还能帮我们自动去生成代码。
ここに画像の説明を挿入


增、删、该操作

接下来,我们来实现⼀下⽤户的增加、删除和修改的操作,对应使⽤ MyBatis 的标签如下:
< insert >标签:插⼊语句
< update >标签:修改语句
< delete >标签:删除语句

接口的定义,还是一样的写法。
写法的差异,主要就体现在 xml 中 的 自定义 SQL 语句 上。


MyBatis 修改操作

我们先给 userinfo表插入一条记录。
ここに画像の説明を挿入
下面,实现 改操作。
ここに画像の説明を挿入
下面我们来拓展几个细节:
1、方法参数 使用 @Param 注解之后,原先参数的名称不能再使用。
ここに画像の説明を挿入
得出结论:
@Param 注解 和 @RequestParam 注解,起着相同的作用。
方法 参数重命名。一旦重命名之后,原来的名称是不能使用的。

只不过 @Param 注解中的参数是 重命名后的结果。
而 @RequestParam 注解中的参数 是参数原名,方法参数是 重命名的结果。

于此同时,我们又发现了一个问题。
当我们测试完之后,我发现此时数据中的数据被 “污染”了!
前面不是说:单元测试不会污染 数据库中的数据嘛?
下面,我们就来实现这个功能。
【免得你们认为我是个老六,说我忽悠你们】


在不修改数据库中数据的情况下,完成单元测试 - 穿插

方法很贱简单,在测试的单元上,加上一个注解@Transactional,就行了。
@Transactional:就是事务的意思。
其作用就是在开始执行测试之前,开启一个事务。
这个事务完成的任务,就是我们定义的是SQL操作。
在 操作完成之后,也就是测试完成之后,该事务会进行一个 “ 回滚 ” 操作。
原来的数据是什么样子的,现在还是什么样子的。

就是说:事务执行的期间确实 “ 污染 ” 了 数据库中的数据,
但是!在事务执行完成之后,事务会通过 “ 回滚 ” 操作,将被 操作的数据还原到未修改的状态。

这里需要注意一点:
@Transactional 注解,原本只是提供一个 自动提交事务的功能。
并不会提供 自动 “ 回滚 ” 功能。
只是说 该 单元测试 所处于的 测试类,是被 @SpringBootTest 注解 修饰的。
等于就是说:“强行” 给 @Transactional “ 加班 ”!!!
无论 单元测试是否成功,都会进行一个 事务的 “ 回滚 ”,将数据库的数据还原!
ここに画像の説明を挿入
我没有晃点你们吧?
只需要在 测试的单元上,再加上一个 @Transactional 注解,就可以在 “ 不污染 ” 数据库中数据的前提下,完成单元测试。

当然,这个操作的大前提:
是在 测试的单元所在的测试类,是被 @SpringBootTest 注解所修饰的。


MyBatis 删除操作

有了 修改操作,删除操作实现起来,就简单很多了。


1、在 mapper 中的 UserInfoMapper 接口中定义 方法

ここに画像の説明を挿入


2、在xml文件中 编写 SQL语句 的相关代码。

注意!只有 select 标签,特殊一点(需要指定返回类型)。
delete 标签 和 update 标签都是一样的。
ここに画像の説明を挿入


单元测试 - 验证功能效果

ここに画像の説明を挿入

有了 修改 和 查询操作的基础,这个删除操作,就跟玩一样。
很快就能搞定!


MyBatis 插入操作

这个插入操作,相比前面 “ 删查改 ” 操作,要复杂一些。
所以,把它放在最后来讲。
操作还是一样的,只是插入的值,是一个对象,在 编写 SQL的时候,如何获取对象的属性,是一个问题。
还有返回值的处理。


先实现最简单 的 插入操作

返回值,返回一个受影响的行数

1、在 mapper 中的 UserInfoMapper 接口中定义 方法

ここに画像の説明を挿入


2、在xml文件中 编写 SQL语句 的相关代码。

ここに画像の説明を挿入


3、进行单元测试

ここに画像の説明を挿入

算了,为了防止你们认为我做假。
我 “污染”一条 王五的信息。
ここに画像の説明を挿入


上面最简单的实现方式,下面我们来看难一点的实现。

现在我们不想 将 影响的行数,作为返回值了。
我要 插入成功的用户信息的ID!
虽然实现的步骤没有变化,但是想要达到预期的效果,还需要做点事。


先来看第二步:在xml文件中 编写 SQL语句 的相关代码。

ここに画像の説明を挿入

对了,我还扩展一下。
在上述 insert 语句中,最好加一个属性:keyColumn。
更保险!
ここに画像の説明を挿入
useGeneratedKeys:
这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键
(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段),默认值:false。

keyColumn:
设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。

keyProperty:
指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值 或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。

简单来说:我们加上 keyColumn 的原因,就是为了确保获取 对应字段。


再来看一步:在 mapper 中的 UserInfoMapper 接口中定义 方法。

返回受影响的行数 和 自增 id
ここに画像の説明を挿入


我们测试一下。

带了这一步,我就不给你们演示如何创建 单元测试了。
这都soEeasy的事情了。
另外,我直接上代码。
看不懂,就返回去看前面的。
ここに画像の説明を挿入
有的人可能会有疑问:自增ID,是有什么问题吗?
其实没问题!
这是因为 MySQL 中的 搜索引擎 InnoDB 的机制,就是这样设计的。

学到这里,就可以将一些 简单的servlet 项目,改成 SSM 项目。


查询操作

单表查询

这个就是前面的 第一个 MyBatis 查询 。
它急救室一个单表查询。

单表查询,就是字面意思:
在一张表中查询数据。

这个我就不重复讲了。
来看下面的重点


参数占位符 #{} 和 ${} 的区别

#{}:预编译处理。
${}:字符直接替换

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的 set ⽅法来赋值。直接替换:
而MyBatis 在处理 ${} 时,就是把 ${} 直接替换成变量的值。
 
这里需要普及的一点:
MySQL中有两种查询:1、叫做及时查询(字符直接替换);2、预查询(预处理)
及时查询:当了需要执行SQL的时候,才会去执行SQL,
预查询:相对于 及时查询,预查询要多出两步:既然查询的参数会变,那先用一个 ?号占位符 顶替参数,先构造好一个SQL,进行预查询,看看SQL的格式有没有错误。
随后,通过 jdbc 的方式来替换 占位符。这样就能保证SQL的正确性。

你可能觉得这麻烦,但是其实!预查询是为了提高查询效率的。
举个例子:ここに画像の説明を挿入

通过上述的代码,只能证明 #{} 和 ${} 对于 查询条件为整形的查询效果是一样,至于效率,只能意会,毕竟,我们感知不到。
但是!安全性,是可以体现的!下面我们就来演示一下。
ここに画像の説明を挿入

由此,不难得出结论:#{}支持所有的数据类型,${} 只支持 数值类型
再举个例子,来加深对 预编译【 #{} 】和字符串替换【 ${} 】之间的区别 的理解

头等舱和经济舱乘机分离的故事:
在坐⻜机的时候头等舱和经济舱的区别是很⼤的,如下图所示:
ここに画像の説明を挿入
⼀般航空公司的客运机都是头等舱和经济舱分离的,头等舱的⼈先登机,登机完之后,封闭头等舱,然后再让经济舱的乘客登机,这样的好处是可以避免有人浑⽔摸⻥,经济舱的⼈混到头等舱的情况,这就相当于预处理,可以解决程序中不安全(越权处理)的问题。

⽽直接替换的情况相当于,头等舱和经济舱不分离的情况,这样经济舱的乘客在通过安检之后可能越权摸到头等舱,如下图所示:
ここに画像の説明を挿入
这就是 直接替换【 ${} 】 所带来的缺陷。
就是说: SQL 没有正确访问它应该访问的地方。
这就是 SQL注入的安全问题。

而且,由于头等舱的票很贵,买的很少。
通常是坐不满的,因此,上述这种 经济舱的人 做到 头等舱也是常有的 。
最好的方法,就是前面说的一下,先让头等舱上机,上完之后。
关闭头等舱的入口,然后,经济舱的人开始上机。
这样就不会存在有 “ 误入 ” 的情况了。

有些人的素质是真的低,买了低价的票,却想着享受高价的服务。
如果不让他如愿,它还恶意举报 航空公司。

所以,出现这种问题的根本原因:就是等级没有分明。
头等舱的门,就相当于是一个界限。
将 头等舱 与 经济舱 分离了。

有的人可能会说:加一个检票员来检查票据。
这样不也能解决问题嘛。
但是!你遇到不讲理的怎么办?
它就是要坐!
它有一大堆歪理由。。。。
这时候,你想把它请出去,非常难!
容易产生纠纷。
所以,不推荐这样去做。

因此,正如前面所说:在登机的时候就把 人员分开。
让优先级高的线上,就不会存在纠纷问题。
同样也很高效。
 
这样就不用做第二次校验,也就不会产生纠纷问题。
即使 头等舱的用户来迟了,叫一个空乘服务人员,专门领他过去,就行了。
领进去,再把门一关。
经济舱的人还是混不进入的。

也就是说:每个人都只经历了一次检验机票,就完成了登机。

那么,问题来了。
既然 #{} 这么无敌,那么,${} 是不是就可以滚蛋了?

NO!
存在,即有意义!【蚊子除外!】
下面,我们来看 ${} 的使用场景。
ここに画像の説明を挿入
其实,与其说是 ${} 的优点,不如说是它的专长!
毕竟 这任务,#{} 做不了,只有它能做!

前面不是说:
使用 ${} 存在 SQL 注入的问题嘛?
现在,哪怕是处于 ${} 的主场,依然也存在着这个问题!
那如何处理呢?

注意事项:
当不得不使用 ${} 时,那么一定要在业务代码中,对传递的值,进行安全校验!
就是说:当代码执行到 mapper 这一层,就没救了!
只能 “ 上战场 ”了。。背水一战。
所以,一定要在业务代码中,对数据校验。
Controller 的作用就体现出来了!
因为 它就是负责对数据的校验。
结合现在的情况:就是对 传递过来的 order 进行 判断非空,长度不能为0,甚至对内容进行校验,是否是 desc 和 asc,其中的一个。

结合生活案例:
我们在上地铁,火车,飞机等公共交通工具的时候,为什么在我们乘坐之前,就开始检查我们的包裹,而不是 上车的时候,检查包裹。
这我们的 ${} 的校验数据,是同一个道理。
为了保证传递的数据的安全性以及正确性。【确认没有违规物品,保证乘客的声明安全】


${} 的经典问题:SQL注入问题

ここに画像の説明を挿入

由上面的例子,相信大家对 SQL注入问题,有了一定了解。
SQL注入问题,就是在我们没有对 传递数据进行校验的前提下。
当我们处于一些特殊场景的时候,可以在不满足获取条件的情况下,获取私密信息。
这对用户信息和 财产的安全隐患是非常巨大的!!!
这就是安全漏洞啊!!!

所以,请一定一定一定切记!在处理一些重要信息的时候,如果使用了 ${},请在 Controller 层,对数据进行严格校验!

我们再来试一下:把 $ 改成 # ,效果会如何?
ここに画像の説明を挿入
由此,不难得出结论:
使用 #{} 是不存在 安全漏洞滴!!!
是非常nice的。


like 查询 - 特殊情况

前面的问题,由于关键字,就那么几个。
直接穷举,很容易在 Controller 层里面 判断数据的正确性。

但是!模糊匹配能穷举吗?
很显然是不能的!
如果数据有个几百万,那我们不得嗝屁!
下面,演示一下。
ここに画像の説明を挿入
此时,问题也就随之而来了!
在进行模糊匹配查询的时候,不能使用 #{} ,否则会报错!
而改用 ${} ,有穷举不了所有的情况。
无法做到完美验证数据的正确性和安全性。

那么,怎么解决这一个问题呢?
使用concat拼接方法,就可以解决问题了。
ここに画像の説明を挿入


#{} 和 ${} 的区别总结

1、定义不同:#{} 预处理:而 ${} 是直接替换

2、使用不同:#{} 适用于所有类型的参数匹配;但 ${} 只适用于数值类型。

3、安全性不同:#{} 性能高,并且没有安全问题;但 $ {} 存在 SQL 注入的安全问题。

4、使用场景不同:
当传递的是一个 SQL 关键字 的时候,只能 使用 ${} 。
当传递的是一个字段,总之,就是需要获取到参数类型 与 内容,只能使用 #{}。
(PS:数字类型,#{} 和 ${} 都是可以使用的!)

5、 ${} 不能用于 模糊匹配查询;而 #{} 需要搭配 concat 才能在模糊匹配中使用。


多表查询

前置知识

返回类型:resultType

这个大家都很熟悉,我们已经在前面的示例中,使用了很多次。
用于指定 SQL 查询结果 映射的对象类型。
但是!这里有一个细节!
ここに画像の説明を挿入
除了修改 实体类属性名称,还有一个方法:使用 下面即将介绍 resultMap。
ここに画像の説明を挿入

返回字典映射: resultMap

resultMap 使用场景:

1、字段名称和程序中的属性名不同的情况,可以使用 resultMap 配置映射、
这个上面演示过了,就不再演示了。

2、一对一和多对多关系可以使用 resultMap 映射并查询数据。


resultType && resultMap 的区别

1、在对象属性名称 与 数据表字段名称,相同的情况下:
使用 resultType 比 resultMap 更爽!

2、在对象属性名称 与 数据表字段名称,不同的情况下:
使用 resultMap 可以指定 不同名称的 字段与属性 的映射关系。


有了 resultMap 和 resultType 的基础,我们下面就可以真正开始进行多表查询的操作了。

在 MyBatis 中,支持的多表查询有两种:
1、 一对一关系:以博客来说,一篇博文只能有一个作者,文章和作者的关系就是一对一。
2、一对多关系:一个作者可以是 多篇博文的作者。都是他写的嘛!作者 和 文章是 一对多的关系。


MyBatis 多表查询:一对一关系

下面,我就来模拟实现一下 一对一的关系。
but!在此之前,我们需要创建关于文章表的实体类。
我们前面只是创建一个 用户表的实体类。
ここに画像の説明を挿入
在进行查询之前,我们先来看一下 articleInfo 表中,有几条信息,信息的内容是什么,这样方便我们后面写代码。

ここに画像の説明を挿入
如果你们的content 出现乱码,反正就不是中文。
你就可以参考这篇文章MySQL第二讲,在文章的最后讲了如何配置字符集的问题ここに画像の説明を挿入

下面,我们去mapper 包中,在创建一个 MyBatis 的接口。
实现根据文章的 id 查询到文章的详情信息。
ここに画像の説明を挿入
咋一看,好像没有问题。但是确实有问题!
ここに画像の説明を挿入
这就很好奇了,文章的 uid 是 1,对应着 用户表中 admin 用户。
就是说:文章的作者,确实是存在的。
那为什么 userinfo是 null 呢?
原因很贱,我们的实体类有这哥属性,但是文章表里没有这个字段啊!
ここに画像の説明を挿入
这个时间,resultMap 就上场了。因为 resultType 它不行!

可参考对数据表进行“增删查改”的进阶操作
ここに画像の説明を挿入
ここに画像の説明を挿入
此时,我们就实现了一对一查询。(存在问题)
【association 标签,就是用来实现一对一情况的多表查询】
虽然存在一些问题:
UserInfoMapper 中 resultMap 配置的字段信息不完整。
导致:虽然查询结果的信息是完整,但是没有完整映射到 ArticleInfoMapper 的 userinfo 属性中。
ここに画像の説明を挿入
这里可以体现出一个结论:
在 本身 xml 文件,是可以不用映射所有属性的信息。
因为 它是自己调用自己,所以,不需要 resultMap 将属性全部映射,都能自动完成所有属性的映射。
而 想要在一个 resultMap 中 调用 另一个 resultMap 中信息,只能是它映射了的信息。
否则无法获取。
所以,我们来讲 UserInfoMapper 中 resultMap 对于属性的映射补全,再来看个效果。ここに画像の説明を挿入
这里还存在着问题:
ここに画像の説明を挿入
到头来,结果发现:还是存在问题的。
当一个属性,在两个数据表中都存在时,默认读取的是 本身的字段值。
也就是说:不光是上面的两个,我们演示的那个情况,出现的那四个属性都是这个情况。
ここに画像の説明を挿入
下面,我们来分析解决这个问题。
同时加深对这个问题的印象。
ここに画像の説明を挿入
这个时候,我们才真正完成了 一对一关系的多表查询!!!!!


MyBatis 多表查询:一对多关系

一对多关系:⼀个⽤户可以是多篇⽂章的作者。
⼀对多需要使⽤ < collection > 标签,⽤法和 < association > 是一样的 .

为什么使用 collection标签,其实很理解。
看中文意思就明白了!
association 的中文就是关联,放到使用场景中,就是将 2个表联系起来。

collection 的中文意思就是 收集(把它理解为集合),将多个表收集起来,整合。
当然,这些表,肯定都与一张表有关系,不管怎么叫做 一对多?
放在实例中,多个表对应着多篇文章,
这多个表中有一个相同字段,且信息是一样的。【作者id是一样,即是同一个人写的】
由这个作者id,就可以把所有文章(是他写的文章)给映射起来,建立关系。
这就是 一对多 关系。

在实现一对多关系查询之前,我们先来做一些准备工作。
首先我们来用户表的实体类进行处理。
ここに画像の説明を挿入
下面我就来实现这个一对多的关系查询。。
实现一个 根据用户id,获取用户和他缩写的文章信息。
ここに画像の説明を挿入
换句来说:
一对多关系的查询,相比于 一对一关系的查询,就是把 resultMap 中的 association 标签,换成了 collection 标签。
里面的内容一点都没改。


复杂情况:动态SQL使⽤

动态 sql 是MyBatis的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接。
可以参考官⽅⽂档:Mybatis动态sql
进去之后就是这个页面
ここに画像の説明を挿入
你会发现 动态SQL,被拎出来,放目录里,说明什么?
说明它重要啊! 不然,我也不会给它一级标题啊。


动态标签 - < if >标签

在注册⽤户的时候,可能会有这样⼀个问题,如下图所示:
ここに画像の説明を挿入
回顾我们之前实现的功能查询,你会发现参数全部都是确定的,就是写死了的。
ここに画像の説明を挿入
都是抱着那种前端一定会传给我数据的 “ 态度 ”,也就是认为一定会拿到必要参数!
但是!在实际业务场景中,会存在一些非必传的参数。
就是说:必要参数,有时候是不会传输的,很有可能传过来的参数,是没有的。
那么,面对这种情况,我们在程序中该如何处理?
ここに画像の説明を挿入
下面,我们就来具体实现这个业务。
ここに画像の説明を挿入
但是存在着一个问题:如果参数很多,而且!每一个参数都是非必传参数。
那么,我们需要对每一个参数进 if 标签来判断。
这就非常的麻烦!可能会多敲字符,导致SQL出现问题。
这个时候,就需要借助 trim 标签了。
具体怎么使用,看下面对 trim 标签的介绍和使用。


动态标签 - < trim >标签

之前的插⼊⽤户功能,只是有⼀个字段可能是非必传,如果有多个字段,⼀般考虑使⽤ < trim >标签 结合 < if >标签,对多个字段都采取动态⽣成的⽅式。
< trim >标签中有如下属性:
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀
prefixOverrides:表示整个语句块要去除掉的前缀
suffixOverrides:表示整个语句块要去除掉的后缀

说白了,trim 就是为了方便程序员 去除 开头 /末尾 的 某个符号
也就是说:在 开头/结尾 ,多写了这个符号,是没有问题的。
因为 trim 会将它删除掉。
如果没多写,也不会影响 程序的运行。
ここに画像の説明を挿入
下面我们来实战演练一波。
ここに画像の説明を挿入


动态标签 - < where >标签

传⼊的⽤户对象,根据属性做where条件查询,⽤户对象中属性不为 null 的,都为查询条件。
如user.username 为 “a”,则查询条件为 where username=“a”:
where标签,主要作用:实现查询中的 where 替换的。
什么意思呢?
原先我们写的 where 是 SQL 的一部分,是SQL的关键字。
现在我们使用 MyBaits 提供是 where 标签来代替 SQL 中 where 关键字 。

那么,有的人可能会有疑问; 这替换跟没替换一样,还多敲 几个箭头。
因此,会产生一个问题: 使用 where 标签 的好处都有哪些?
不然不会创造出一个 where标签出来。
如果没有任何查询条件的情况下,where 标签 可以实现 隐藏 SQL 的 where 的SQL部分;但如果存在查询条件,那么会生成 where的 SQL,并且 where 标签可以自动的去除最后一个 判断条件的 and 字符。

也就是说:我们在拼接多个条件的时候,有几个条件涉及到非必传参数。
会有一个什么情况呢?
通常 我们拼接多个条件的时候,要么使用 or(或逻辑),要么使用 and(与逻辑)。
A and B;
当 A 条件,缺少判断的参数的时候,就会将 A 和 后面 的 and 去除掉。
这个and也就是最前面一个 and 嘛。
就变成一格判断条件的 SQL了。

下面,我们来实战一下。
ここに画像の説明を挿入
虽然比直接敲SQL,要复杂一点点。
但是,构造 SQL的灵活性,大大提高!

还有一个去除 and 的功能,对吧?
我们再来搞一下。
ここに画像の説明を挿入
如果 and 放在后面,就是说 and 后面没有判断条件,或者说 缺少 参数,无法构造 where SQL。会出现什么状况?
我已经帮你们测了,报错!
ここに画像の説明を挿入
其实这个问题也很好解决。直接给你们演示个大概。
ここに画像の説明を挿入
以上标签也可以使⽤ < trim prefix=“where” prefixOverrides=“and” > 替换。
无非就是 少用几个属性。


动态标签 - < set >标签

根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。
UserMapper 接⼝中修改⽤户⽅法:根据传⼊的⽤户 id 属性,修改其他不为 null 的属性:
这么说吧。set 标签,和 where 是一样。
都是替代 SQL 中的关键字。
set 就是 update 操作所需要使用的关键字。
而且,也是和 if 标签 配合使用的。

而且和 trim 标签一样。可以去掉最后一个符号(一般都是逗号)。
ここに画像の説明を挿入
实战演示一波。
ここに画像の説明を挿入
那如果没有 逗号呢?会是什么效果?
下面我们把三个非必传参数都传递。
ここに画像の説明を挿入
以上标签也可以使⽤ < trim prefix=“set” suffixOverrides=“,” > 替换。


动态标签 - < foreach >标签

このタグは、コレクションをトラバースするときに使用できます。<foreach> タグには次の属性があります。
collection: List、Set、Map、または配列などのバインディング メソッド パラメータ内のコレクション オブジェクト
item: トラバーサル中の各オブジェクト (コレクション内の要素)
open: の先頭の文字ステートメント ブロック文字列 (trim のプレフィックスに類似)
close: ステートメント ブロックの末尾の文字列 (trim の終了に類似)
セパレーター: 各トラバーサル間の間隔の文字列 (スペーサー)
[PS: foreach ラベル、トリムでは交換できません!

アプリケーション シナリオ:
通常、1 つずつではなく、データベース内の情報を削除します。
代わりに、たくさん削除します。
例:
ID に従ってレコードを削除する場合は、これらの ID の組み合わせを作成します。
ここに画像の説明を挿入
この時点で、foreach タグを使用してパラメーターをトラバースし、対応する情報を削除できます。
これは非常に効率的で、削除する必要があるすべてのデータを 1 回の呼び出しで削除できます。

実践的なデモンストレーションの波。
ここに画像の説明を挿入

Supongo que te gusta

Origin blog.csdn.net/DarkAndGrey/article/details/126103652
Recomendado
Clasificación