目次
springboot は mybatisplus 設定ファイルを統合します
エンティティクラスUserを定義した後、マッパーインターフェイスを編集します。
@Mapper と @MapperScan("パッケージ名") の違い
コンストラクターに従って主キーフィールドのコレクションをクエリします。
条件コンストラクターに従って複数のユーザーにクエリを実行する
変更が必要なエンティティクラスにバージョンアノテーションを追加します。
マイバティスプラス
意味: mybatis-plus は、mybatis の拡張ツールです。mybatis をベースに、変更は加えずに拡張のみが行われます。開発を簡素化し、効率を向上させるために生まれました。
注: mybatis に基づいて mybatisplus を直接統合できますが、これは mybatis の機能には影響しません。また、mybatis が提供する機能を使用することもできます。
MPの機能
- mybatis には機能強化のみが行われ、変更は行われません。導入しても既存のプロジェクトには影響しません。
- 単一テーブルの CRUD 操作を迅速に実行するための簡単な構成のみが必要なため、時間を大幅に節約できます
- コード生成、自動ページネーション、論理削除、自動埋め込み機能などが利用可能
MPフレーム構造
理解する:
- MP は MP スターター、アノテーション部、拡張部、コアコア部、コード生成部で構成されており、これらの内容が MP の機能を実現するプロセスをサポートします。
- MP実装機能:まずエンティティクラスをスキャンし、スキャン後のリフレクション技術を通じてインスタンスクラスの属性を抽出し、抽出後のテーブルとエンティティクラスの関係と、リフレクションを通じて抽出されたエンティティクラスの属性を分析します。現在のフィールド間の関係、現在呼び出しているメソッドに従って対応する SQL ステートメントを生成し、追加、削除、変更、クエリの SQL ステートメントを mybatis コンテナに注入して、最終的な機能を実現します。
MP使用の準備
依存関係をインポートする
<dependencies>
<!--springboot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--springboot测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--MP启动器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动包--><!--测试功能的启动器-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
springboot は mybatisplus 設定ファイルを統合します
spring:
#设置数据源信息
datasource:
#配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT%2B8
username: root
password: root
mybatis-plus:
configuration:
#MP提供了日志功能
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#驼峰映射(默认就是开启的)
map-underscore-to-camel-case: true
#设置MP的全局配置
global-config:
db-config:
#这样设置的话,那么实体类所有的表都会加上t_前缀
table-prefix: t_
#设置统一主键生成策略
id-type: auto
#映射文件路径
mapper-locations: classpath:/mapper/UserMapper.xml
#配置类型别名所对应的包
type-aliases-package: cn.tedu.mybatisplus.pojo
#扫描通用枚举的包
type-enums-package: cn.tedu.mybatisplus.enums
エンティティクラスUserを定義した後、マッパーインターフェイスを編集します。
//使用MP提供的通用mapper——BaseMapper
//BaseMapper里的泛型表示实体类的类型
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
知らせ:
- MP は一般的に使用される多くの CRUD メソッドをカプセル化するため、ユーザーは必要なときにのみパブリック ビジネス インターフェイス BaseMapper を継承する必要があるため、効率が向上します。
- ジェネリックは、ジェネリック オブジェクトに従って、指定されたアノテーション (およびアノテーションの値を取得)、テーブル名、およびその属性を取得する必要があるため、BaseMapper インターフェイスに追加する必要があります。
@Mapper と @MapperScan("パッケージ名") の違い
- @MapperScan("パッケージ名"):指定されたパッケージの下のマッパーインターフェイスをスキャンし、インターフェイスのプロキシクラスをストレージのためにSpringコンテナに渡します
- @Mapper:インターフェイスのプロキシ クラスをストレージ用の Spring コンテナに渡します
- @Mapper は指定されたインターフェイスで使用され、 @MapperScan("対応するインターフェイスのパッケージ名") は起動クラスまたは構成ファイルで使用されます
MPの基本操作
注:使用前に userMapper を挿入してください
追加操作
User user = new User();
user.setName("lili").setAge(23).setEmail("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
//mybatis-plus会自动获取id
System.out.println(user.getId());
削除操作
IDでユーザーを削除
int i = userMapper.deleteById(7);
System.out.println(i);
条件としてマップによる削除
Map<String,Object> map=new HashMap<>();
map.put("name", "张三");
map.put("age", 23);
//删除name为张三,age为23的人
int i = userMapper.deleteByMap(map);
System.out.println(i);
複数のIDで削除
List<Long> list = Arrays.asList(1L, 2L, 3L);
int i = userMapper.deleteBatchIds(list);
System.out.println(i);
ユーザーを更新する
IDによるユーザー更新
User user = new User();
user.setId(3L).setName("lan").setEmail("[email protected]");
//根据id修改元素
int i = userMapper.updateById(user);
System.out.println(i);
ユーザーに問い合わせる
ID でユーザーをクエリする
User user = userMapper.selectById(1L);
System.out.println(user);
複数の ID に基づいてユーザーをクエリする
List<Long> list = Arrays.asList(1L, 2L, 3L);
List<User> users = userMapper.selectBatchIds(list);
users.forEach(System.out::println);
マップコレクションを条件としてユーザーにクエリを実行します
HashMap<String, Object> map = new HashMap<>();
map.put("name", "lan");
map.put("age", 28);
List<User> users = userMapper.selectByMap(map);
//list会直接打印对象数组
System.out.println(users);
共通サービスインターフェース
説明:一般サービスは、IService インターフェイスをカプセル化し、マッパー レイヤーを区別して混乱を避けるために、クエリ単一行の取得、削除削除、リスト クエリ コレクション、ページ ページネーション、およびその他のプレフィックス命名メソッドを使用して CRUD をさらにカプセル化します。
//service接口
public interface UserService extends IService<User> {
}
//service实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
知らせ:
- ServiceImpl<UserMapper, User> は IService<User> インターフェイスを実装します
- 使用する場合は、UserService を最初に挿入する必要があります。
いくつかの操作
レコードの総数を問い合わせる
//查询总记录数
long count = userService.count();
System.out.println(count);
データをバッチで追加する
ArrayList<User> list = new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
User user = new User();
user.setName("cjc"+i).setAge(10+i);
list.add(user);
}
//批量添加数据
boolean b = userService.saveBatch(list);
//操作成功或失败
System.out.println(b);
MP の一般的な注釈
//设置实体类所对应的表名,若对象与表名一致,则表名中()可以省略
@TableName("t_user")
public class User {
//将当前属性对应的字段指定为主键(将该属性与数据库中的id字段进行映射),并通过雪花算法生成主键id
//type标识主键的生成策略为自动递增,要求数据库的主键为自增策略(默认为雪花算法——IdType.ASSIGN.ID)
@TableId(value = "id")
private Long id;
//将该注解标识的属性与数据库中的name字段一一映射,若属性名与字段名相同,则注解可省略
@TableField(value = "name")
private String name;
private Integer age;
private String email;
//逻辑删除0标识未删除,1标识已删除
//被逻辑删除的数据用户查不到,但是可以在数据库中看到,只是该属性变为1;(为修改操作)
@TableLogic
private Integer isDeleted;
}
注: @TableField(exit=false) アノテーションは通常、挿入された属性で使用され、このアノテーションによって識別されるテーブル名の現在の属性は MP の操作には関与しません。
スノーフレークアルゴリズム
序文
背景:アクセス圧力とデータ量の増大に対処するために、データ規模の増大に対処する適切なソリューションが必要です。
データベーステーブルの拡張方法:業務サブデータベース、マスタースレーブレプリケーション、データベースサブテーブル
データベーステーブルの2つの分割方法
- 垂直テーブル
- レベル表
垂直テーブル
重要なデータを 1 つのテーブルに配置し、ビジネス クエリで使用されないデータを別のテーブルに分離することで、特定のパフォーマンスを向上させることができます。
レベル表
主キー自動インクリメント:例えばテーブルを範囲で分割(テーブル1には1~9999、テーブル2には10000~20000を入れる)
モジュロ:主キー% データベース数、同じ余りをテーブルに入れる
スノーフレークアルゴリズム:
Snowflake アルゴリズムは Twitter 分散主キー生成アルゴリズムであり、異なるテーブルの主キーの重複のないことと、同じテーブルの主キーの順序付けを保証します。
本旨:
- 長さは64bitです
- 1つ目は符号ビット、1ビット識別です。javaではlongの基本型が符号化されているため、最上位ビットは符号ビットで、正の数は0、負の数は1であるため、idは通常正の数になります。最上位ビットは0です
- 4bitはタイムスタンプ(msレベル)で、タイムスタンプの差分(現在のタイムスタンプ - 開始タイムスタンプ)を格納しており、結果は約69.73年となります。
- マシン ID として 10 ビット (5 ビットはデータセンター、5 ビットはマシン ID、1024 ノードに展開可能)
- ミリ秒以内のシリアル番号として 12 ビット (各ノードがミリ秒あたり 4096 個の ID を生成できることを意味します)
利点:全体的に時間増分に従ってソートされ、分散システム全体で ID の衝突が発生しません。
条件付きコンストラクター
役割:現在の状態をカプセル化する
継承構造
AbstractWrapper:条件付きクエリのカプセル化に使用され、SQL を生成するための条件が指定されます。
- QueryWrapper:クエリ条件のカプセル化
- UpdateWrapper:条件付きパッケージの更新
- AbstractLambdaWrapper:ラムダ構文を使用する
抽象ラムダラッパー
- LambdaQueryWrapper:ラムダ構文の使用のためのクエリ ラッパー
- LambdaUpdateWrapper:ラムダ更新パッケージ ラッパー
条件付きコンストラクターを使用してクエリ操作を実装する
すべてのユーザーにクエリを実行する
//通过条件构造器查询一个list集合,若没有条件则可以设置null(相当于查询所有)
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
コンストラクターに従って主キーフィールドのコレクションをクエリします。
//查询name为lei的主键字段
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "lei");
List<Object> list = userMapper.selectObjs(queryWrapper);
System.out.println(list);
条件コンストラクターに従って複数のユーザーにクエリを実行する
//查询用户名包含a,年龄在20-30之间,邮箱信息不为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//queryWrapper可以实现链式加载
queryWrapper.like("name", "a").between("age", 20, 30).isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
//对象形式
User user = new User();
user.setAge(28);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
//user内的属性最终会以and形式拼接
ファジークエリについて
- like:の両側に % があることを示します。
- likeleft:の左側に % があることを示します。
- likeright:の右側に % があることを示します。
クエリ内
//in查询,查询id为1,2,3的数据
Integer[] ids={1,2,3};
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id",ids);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
エスケープ文字によるクエリと並べ替え
//查询id>2的用户,按照年龄降序排序,若年两相同则按照id升序排序
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("id", 2).orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
エスケープ文字
- >:GT
- <:lt
- =:等価
- >=:げ
- <=:
- != : は
条件付きコンストラクターは削除操作を実装します。
//删除邮箱地址为null的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
int i = userMapper.delete(queryWrapper);
System.out.println(i);
条件付きコンストラクターを使用した変更操作の実装
//将年龄>20并且用户名中包含a或邮箱为null的用户进行修改(默认情况下就是and连接)
//修改条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20).like("name", "a").or().isNull("email");
User user = new User();
user.setName("lei").setEmail("[email protected]");
int i = userMapper.update(user, queryWrapper);
System.out.println(i);
条件の優先順位
//将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息进行修改
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//lambda中的条件优先执行(i就表示条件构造器)
queryWrapper.like("name", "a").and(i-> i.gt("age", 20).or().isNull("email"));
User user = new User();
user.setName("red").setEmail("[email protected]");
int i = userMapper.update(user, queryWrapper);
System.out.println(i);
select ステートメントの組み立て
//查询出来一个以map为泛型的list集合
//查询用户名、年龄、邮箱信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name","age","email");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
System.out.println(maps);
サブクエリの組み立て
//select * from t_user where id in(select id from t_user where id<=100)
//查询id<=100的用户信息
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("id", "select id from t_user where id<=100");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
動的SQLクエリ
String name=null;
String age="21";
//判断字符串是否为null或空串若为返回false,不为返回true
boolean pn = StringUtils.hasLength(name);
boolean pa = StringUtils.hasLength(age);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//判断属性是否为true,为true则执行该条件,不为则忽略该条件
queryWrapper.eq(pn,"name",name).eq(pa, "age", age);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
注: queryWrapper.clear(); 冗長な条件をクリアするには、クリアした後も queryWrapper を引き続き使用できます。
updateWrapper を使用して変更関数を実装する
//查询用户名中包含a(年龄>20或邮箱为null)的员工信息
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//修改条件
updateWrapper.like("name", "a").and(i->i.gt("age", 20).isNull("email"));
//修改内容
updateWrapper.set("name", "lala").set("email", "[email protected]");
int i = userMapper.update(null, updateWrapper);
System.out.println(i);
LambdaQueryWrapper
機能:私たちが愚かになりすぎて間違ったフィールド名を書いてしまうのを防ぎ、エンティティ クラスの特定の属性にアクセスするための関数インターフェイスを提供します。属性にアクセスすると、属性 Name の対応するフィールドを自動的に取得できます。条件として使用するフィールド
String name="a";
Integer ageBegin=null;
Integer ageEnd=30;
//主要避免了名称写错进而提供了直接访问表达式::
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(StringUtils.isNotBlank(name), User::getName,name)
.ge(ageBegin!=null, User::getAge,ageBegin)
.le(ageEnd!=null, User::getAge,ageEnd);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
System.out.println(users);
LambdaUpdateWrapper
//查询用户名中包含a(年龄>20或邮箱为null)的员工信息
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
//修改条件
updateWrapper.like(User::getName, "a").and(i->i.gt(User::getAge, 20).isNull(User::getEmail));
//修改内容
updateWrapper.set(User::getName, "lala").set(User::getEmail, "[email protected]");
int i = userMapper.update(null, updateWrapper);
System.out.println(i);
MP用ページネーションプラグイン
構成構成クラス (必須)
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//创建mybatisplus拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//向拦截器中添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
MP はページングを実装します
//测试类内
//两个参数——当前页页码,每页信息条数
Page<User> page = new Page<>(2,3);
//两个参数——分页对象,条件构造器
userMapper.selectPage(page, null);//因为我对所有的查询所以条件构造器为null——返回值还为page
//获取当前页数据
List<User> records = page.getRecords();
System.out.println(records);
//获取总记录数
long total = page.getTotal();
System.out.println(total);
//获取总页数
long pages = page.getPages();
System.out.println(pages);
//是否有下一页
System.out.println(page.hasNext());
//是否有上一页
System.out.println(page.hasPrevious());
カスタムページング機能
//自定义接口:
//mybatisplus提供的分页对象,必须为于第一个参数的位置
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
//自定义配置文件sql
<select id="selectPageVo" resultType="User">
select id,name,age,email from t_user where age>#{age}
</select>
//测试类
Page<User> page = new Page<>(2, 2);
userMapper.selectPageVo(page,20);
//获取当前页数据
List<User> records = page.getRecords();
System.out.println(records);
//获取总记录数
long total = page.getTotal();
System.out.println(total);
//获取总页数
long pages = page.getPages();
System.out.println(pages);
//是否有下一页
System.out.println(page.hasNext());
//是否有上一页
System.out.println(page.hasPrevious());
MP オプティミスティック ロック
変更が必要なエンティティクラスにバージョンアノテーションを追加します。
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version//用来标识乐观锁版本号字段
private Integer version;
}
オプティミスティックロックプラグインを追加
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//创建mybatisplus拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//向拦截器中添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
テスト
注:以下の Xiao Wang と Xiao Li は同じデータを使用しています
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李"+productLi.getPrice());
//小王查询商品价格
Product productWang = productMapper.selectById(1);
System.out.println("小王"+productWang.getPrice());
//小李将商品价格+50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格-30
productWang.setPrice(productWang.getPrice()-30);
int result = productMapper.updateById(productWang);
if (result==0){
//操作失败后重试
Product productNew = productMapper.selectById(1);
productNew.setPrice(productNew.getPrice()-30);
productMapper.updateById(productNew);
}
一般的な列挙
エンティティクラスには列挙型があるので、データベースに列挙型を格納する方法
//为该枚举添加注解
@Getter
public enum SexEnum {
MALE(1,"男"),
FEMALE(2,"女");
@EnumValue//将注解所标识的属性的值存储到数据库中(因为数据库中存放的是数字)
private Integer sex;
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
一般的な列挙型スキャン パッケージを構成する
mybatis-plus.type-enums-package=cn.tedu.mybatisplus.enums
列挙されたオブジェクトをデータベースに挿入します
MP自動入力機能
構成クラスの追加
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("created", new Date(), metaObject);
this.setFieldValByName("updated", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updated", new Date(), metaObject);
}
}
エンティティクラスにアノテーションを追加する
@Data
@Accessors(chain = true)
public class Product {
private Long id;
private String name;
private Integer price;
//在插入数据时自动填充
@TableField(fill = FieldFill.INSERT)
private Date created;
//在插入和更新操作时自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated;
@Version//用来标识乐观锁版本号字段
private Integer version;
}
テスト
//测试
Product product = new Product();
product.setName("cake").setId(3L).setPrice(66);
int insert = productMapper.insert(product);
System.out.println(insert);