目次
MyBaits に関する知識はより深く、より詳細なので、読みやすさを考慮して 2 つの記事に分かれています。
1. Mybatis はデータベースの基本的な CRUD を操作します (この記事)。
2. Mybaits で動的 SQL の一般的に使用される 5 つのタグ。
1. マイベイツとは何ですか?
MyBaits は、カスタム SQL、ストアド プロシージャ、および高度なマッピングをサポートする非常 に強力な永続層フレームワークです。Mybaits はJDBC に基づいていますが、JDBC のほとんどすべてと、パラメータの設定と結果セットの取得の作業が不要になります。MyBaits は、単純な XML または注釈を使用して、プリミティブ型、インターフェイス、および Java オブジェクトをデータベース内のレコードとして構成およびマッピングできます。
つまり、MyBaits はプログラムとデータベースの間でより簡潔にやり取りできます。
マイベイトの学習パス:
MyBaits とは何かを理解する → MyBaits フレームワークを Java プロジェクトに追加する方法を学ぶ → MyBaits を初期化する (データベースへの接続、XML の構成など) → 基本的なデータベース CRUD 操作を学ぶ → 動的 SQL (MyBaits のキー) を理解する → 一般的に使用されるいくつかの動的 SQL をマスターするタグ
2. MyBaits 環境を構築します。
2.1 Spring プロジェクトを作成し、Mybaits フレームワークの依存関係を追加します。
2.2 MyBaits 構成情報を設定します。
(1) まず、application.properties 構成ファイルでデータベースに接続します。
依存関係を導入する際にデータベースドライバーであるMySQL Driverを特別に導入するため、ここでドライバーのクラス名を設定する必要がありますが、MySQLであればクラス名は以下の通りなので非常に簡単です。
#MySQL ドライバーのクラス名を設定します
spring.datasource.driver-class-name= com.mysql.cj.Driver
MyBaits が XML 構成を通じてデータベース データをマップする必要がある場合は、対応する XML ファイルが必要であり、MyBaits 構成ファイルに XML ファイルのパスを設定する必要があります (mapper-locatins)。リソースディレクトリに対応するXMLファイルを作成し、統一ファイル名がxxxMapper.xmlの場合、パス設定時に*Mapper.xmlと記述します。
#MyBaits の XML パス = すべてのクラスのルート ディレクトリを設定します: /mybatis directory/名前が Mapper.xml で終わるすべての XML ファイルはmybatis.mapper-locations= classpath:/mybatis/*Mapper.xmlが現在マップされます。マイバチ
3. MyBaits の設計パターンを理解します。
まず、Mybaits のメインツールは 2 つの部分で構成されます。インターフェイス + XML。
- インターフェイス: MyBaits は永続化レイヤーのツールであるため、標準の階層化に準拠するために、他のレイヤーによって挿入されたインターフェイス、オブジェクトなどを受け入れる必要があります。
- xml : xml ファイルに特定の SQL ステートメントを実装します。
MyBaits はインターフェイスと XML を結合してカプセル化し、注入できないインターフェイスを注入できるプロキシ オブジェクトに変換します。このプロセスはユーザーに対して透過的です。
したがって、データベース内のデータとオブジェクトがマッピングされ、データとオブジェクト間の相互変換が完了することが実現されます。
例えば:
- データベーステーブル <——> クラス;
- レコード (行データ) <——> オブジェクト;
- フィールド <——> オブジェクトの属性。
MyBaits 運営データベース:
次に、MyBaits を通じてデータベースの操作を開始します。
事前作業:
(1) データベースとテーブルを構築します。
準備: まず MySQL で mycnblog データベースを作成し、次にいくつかのテーブルを追加します。
-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;
-- 使用数据数据
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 timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
`state` int default 1
) default charset 'utf8mb4';
-- 创建文章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
uid int not null,
rcount int not null default 1,
`state` int default 1
)default charset 'utf8mb4';
-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
vid int primary key,
`title` varchar(250),
`url` varchar(1000),
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
uid int
)default charset 'utf8mb4';
-- 添加一个用户信息
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);
(2) エンティティクラスを追加します。
オブジェクトを通じてデータベースを操作するには、まず対応するエンティティ クラスが必要です。ここでは、userinfo テーブルに対応するユーザー エンティティ クラス USer を追加します。
userinfo テーブルのフィールド情報に従って、エンティティ クラスと 1 対 1 属性を設定します。
package com.example.demo.entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class User {
private Integer id;
private String username;
private String password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private Integer state;
}
(3) マッパーインターフェイスを追加します。
マッパー インターフェイスは、他のレイヤーによって挿入されたインターフェイス、メソッド、オブジェクトを受け取り、xml を結合することによってデータベース データとのマッピングを完了するために使用されます。マッパー インターフェイスの作成は特別なマッパー ディレクトリに配置されます。
ここでは、userinfo テーブルを操作するために特別に使用されます。そのエンティティ クラスは User で、最初に UserMapper インターフェイスを作成します。
注: MMapper インターフェイスが作成されたらすぐに @Mapper アノテーションを追加してください。!!!
package com.example.demo.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
}
(4) UserMapper.xml を追加します。
これは、上で説明した MyBaits の 2 つの主要なツールのうちの 2 つ目でもあります。MyBaits の xml ファイル、つまり、Mapper インターフェイスと組み合わせて使用される xml ファイルです (xml ファイルには多くの種類があるため、明確に区別する必要があります) )、これはまさにデータ永続層の特定の実装です。このようなすべての XML ファイルのパスは、最初に構成された mybatis-locations パスと一致している必要があります。
まず、固定フォーマットがあります。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
</mapper>
- <mapper><mapper> タグ: namespace 属性を指定する必要があります。これは名前空間を意味し、その値はMapper インターフェイスの完全なパッケージ名とクラス名です。
- マッパー タグ内のサブタグ、つまり、黄色のボックス内の <select>、<insert>、<update> およびその他のタグは、特定の SQL を実装するために使用されます。
- サブタグに関する注意点:
- ID は Mapper インターフェイスのメソッド名に対応する必要があります。
- 戻り値の型は必要に応じて入力されます。
2 つの戻り値の型を理解します。
XML には、 resultTypeとresultMap という 2 つの戻り値の型があります。
戻り値の型の機能は、MyBatis が結果のマッピングを行うことです。
クエリ操作の場合は、戻り値の型を設定する必要があります。
追加、削除、変更などの操作の場合、戻り値の型は必須ではありません。
(1)結果の種類:
最も利用シーンが多いタイプで、完全なパッケージ名からクラス名まで直接定義できる利便性が高いのがメリットです。
(2)結果マップ:
辞書マッピングを返します。特定の使用シナリオがあります。
- フィールド名がプログラム内のエンティティ クラスの属性名と異なる場合は、resultMap マッピングを構成できます。
- 1 対 1 および 1 対多の関係は、resultMap を使用してマッピングできます。
最初のタイプを示します: フィールド名と属性名が異なります
データベースのパスワードはpasswordで、UserMapperエンティティクラスの属性名は確かにpwdです。
クエリの結果はエラーを報告します: pwd が検出できません
resultMap を使用してマッピング関係を設定します。
<mapper namespace="com.example.demo.mapper.UserMapper">
<resultMap id="baseMap" type="com.example.demo.entity.User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="password" property="pwd"></result>
</resultMap>
<select id="getByPwd" resultMap="com.example.demo.mapper.UserMapper.baseMap">
select * from userinfo where password=#{pwd}
</select>
</mapper>
ここで実行した結果は次のようになります。
(詳細)ただし、 @Param() を使用してパラメータを渡すときに属性名をフィールド名と同じ名前に変更すると、resultMap マッピングを設定するために苦労する必要はありません。
resultMap 設定マッピングの原理:
実際、このプロセスは結果のクエリによって分割されます。インターフェイスがパラメータを取得したら、そのパラメータを XML 内の {} に渡して照合し、次に SQL を結合して実装のためにデータベースに渡します。終了後に値が MyBatis に返されると、resultMap はこの時点でフィールドと属性に一致します。
2 番目と 3 番目のタイプ: 1 対 1 テーブル マッピングと 1 対多テーブル マッピング (不要なスペースを増やさないように、後続の記事で特別に説明します)
1. クエリ操作:
1.1 単純なクエリ:
以下は、単純なクエリ関数を示しています。
(1) Mapper インターフェイスに関連メソッドを実装します。
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
// 查询所有用户
List<User> getAllUser();
}
(2) UserMapper.xml ファイルに特定の SQL を実装します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getAllUser" resultType="com.example.demo.entity.User">
select * from userinfo
</select>
</mapper>
(3) UserService クラスと UserController クラスを実装します。
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getAllUser() {
return userMapper.getAllUser();
}
}
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getAllUser")
private List<User> getAllUSer() {
return userService.getAllUser();
}
}
起動後にクエリ結果を確認します。
導入する SQL 実行の種類が多いことを考慮し、URL 経由ですべてにアクセスして参照するのは非常に面倒なので、SQL レコードを設定して出力し、単体テストを実行します。
mybatis によって実行された SQL を出力します。
application.properties ファイルでの構成を続けて、次の 2 つの文を追加します。
#打印 MyBaits 执行的 SQL
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
logging.level.com.example/demo=debug
単体テスト:
Mapper インターフェイスで、右クリック - 生成 - テスト... - テスト メソッドの確認 - テスト クラスとテスト メソッドの生成 - テスト クラス @SpringBootTest への注釈の追加 - UserMapper オブジェクトの挿入 - 特定のテスト メソッドの実装
ここに移動して、すべての構成と簡略化された操作を実行し、引き続き追加、削除、変更、確認などの操作を導入します。
1.2 条件付きクエリ:
すべての条件付きクエリには条件付き一致が含まれるため、ユーザーの観点からは、パラメーターをメソッドに渡し、SQL でパラメーターを照合する必要があります。
動的パラメータのパラメータマッチングには2 つの方法があります
- #{paramName} - プレースホルダー パターン。
- ${paramName} - 直接置換。
以下は、これら 2 つの一致を使用した例を示しています。
#{} 形状:
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
// 按照姓名查询
User getUserByName(@Param("username") String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getUserByName" resultType="com.example.demo.entity.User">
select * from userinfo where username=#{username}
</select>
</mapper>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void getUserByName() {
String username = "zhangSan";
User user = userMapper.getUserByName(username);
System.out.println(user);
}
}
${} 形式:
その他は変更する必要はありません。UserMapper.xml の SQL ステートメント部分のみを変更します。
<select id="getUserByName" resultType="com.example.demo.entity.User">
select * from userinfo where username='${username}'
</select>
結果に示されているように、${} は直接置換のロジックです。つまり、文字列を記述するときに一重引用符を追加することを忘れてはなりません。また、#{} はプレースホルダーのロジックであり、パラメータを自動的に置き換えます。適応的な調整を行います。
1.3 のようなファジークエリ:
特殊なケース: ファジー クエリのように実行したい場合、2 つのどちらを使用する必要がありますか?
#{} を使用すると、一致したパラメーターに一対の単一引用符が自動的に追加されるため、エラーが報告されます。
${} を使用した場合: バレることはできますが、SQL インジェクションの危険性を防ぐため、直接使用することはできません。!!
SQLインジェクション:
次の例では、クエリ時にユーザー名とパスワードが正しく一致している必要がありますが、このときのパスワードの入力は非常に特殊で、このドアに属さない鍵を取得するのと同じように SQL インジェクションを実現しますが、そのようにして、彼はドアを開け、中にあるすべての情報を目にしました。
なぜそれが判明したのでしょうか?の後にも or があり、後者の or の条件が満たされている限り、すべてが判明します。
<<< 正しいファジー クエリでは、文字の結合に組み込みの concat スプライシング関数を使用する必要があります。 >>>
<select id="getUserByLike" resultType="com.example.demo.entity.User">
select * from userinfo where username like concat('%',#{username},'%')
</select>
1.4 複数テーブルのクエリ:
マルチテーブル クエリを実行するには、他のテーブルのエンティティ クラスが必要ですが、ここでは、現在のライブラリのarticleinfo テーブルに対応する Article クラスがエンティティ クラスとして選択されています。
まず、Article エンティティ クラスを追加します。
@Data
public class Article {
private int id;
private String title;
private String content;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private int uid;
private int rcount;
private int state;
}
記事テーブルに著者情報が存在しないことを考慮して、Article クラスを継承して別の ArticleVO エンティティ クラスを拡張クラスとして追加します。つまり、目的の記事の詳細が見つかった場合、記事テーブルの列フィールドだけが表示されるわけではありません。 、ただし、対応する著者も表示されます。
public class ArticleVO extends Article {
private String username; // 表示查询出来的文章是哪个作者写的
}
上記も分離です。エンタープライズで、ある企業が複数テーブルのクエリを実行する場合、相互に追加するフィールドが多数あるとします。各エンティティ クラス内に必要な属性をすべて追加することは不可能なので、拡張クラスの継承を解除すると、冗長性と結合が削減され、開発効率が向上します。
複数テーブルのクエリを開始しましょう。
mycnblog ライブラリのarticleinfo テーブルと userinfo テーブルをクエリします。目的は、記事の詳細な説明とそれに対応する著者を見つけることです。記事の詳細はarticleinfo テーブルにあり、著者情報は userinfo テーブルにあります。
まず、マルチテーブルクエリの場合、メインテーブルはarticleinfoテーブルであり、userinfoテーブルのusernameフィールドは外部接続部分である必要があることは明らかです。そのため、今回はクエリメソッドとSQLを完了する必要があります。 Articleinfo テーブルの基礎。
(1) ArticleMapper インターフェイスを追加し、複数テーブルのクエリ メソッドを追加します。
@Mapper // 一定不要忘记注解
public interface ArticleMapper {
// 多表查询
ArticleVO getFromTwoTables(@Param("id") int id);
}
(2) ArticleMapper.xml に SQL を実装します。
<mapper namespace="com.example.demo.mapper.ArticleMapper">
<select id="getFromTwoTables" resultType="com.example.demo.entity.vo.ArticleVO">
select a.*, u.username from articleinfo a
join userinfo u on a.uid=u.id
where a.id=#{id}
</select>
</mapper>
(3) テストメソッドを追加します。
@SpringBootTest
class ArticleMapperTest {
@Autowired
private ArticleMapper articleMapper;
@Test
void getFromTwoTables() {
int id = 1;
ArticleVO articleVO = articleMapper.getFromTwoTables(id);
System.out.println("文章详情:" + articleVO);
}
}
結果:
上記の一連のクエリ操作をマスターしていれば、以下の内容を簡単に追加、削除、変更することができます。
2. 挿入操作:
ここから操作を追加、削除、変更すると、データ テーブルの内容に影響を与える可能性があります。単純なテストでデータ テーブルが変更されない場合は、単体テスト メソッドに @Transactional アノテーションを追加できます。これは、トランザクション操作を追加し、その後ロールバックすることを意味します。テーブル内のデータが操作されます。
これらの操作の XML で戻り値の型を追加、削除、変更します。
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
// 新增用户
int addUser(User user);
}
<insert id="addUser">
insert into userinfo (username,password) values(#{username}, #{password})
</insert>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void addUser() {
String username = "zhaoLiu";
String password = "666666";
User user = new User();
user.setUsername(username);
user.setPassword(password);
int ret = userMapper.addUser(user);
System.out.println("新增了 " + ret + " 行");
}
}
3. 削除操作:
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
// 删除用户
int deleteUserByName(@Param("username") String username);
}
<delete id="deleteUserByName">
delete from userinfo where username=#{username}
</delete>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void deleteUserByName() {
String username = "zhaoLiu";
int ret = userMapper.deleteUserByName(username);
System.out.println("删除了 " + ret + " 行");
}
}
4. 操作を変更します。
@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
// 修改操作
int update(@Param("username")String username, @Param("password")String password);
}
<update id="update">
update userinfo set username=#{username}
where password=#{password}
</update>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void update() {
String username = "张三";
String password = "111111";
int ret = userMapper.update(username,password);
System.out.println("修改了 " + ret + " 行");
}
}