首頁 > 軟體

MyBatis-Plus 條件查詢器的實現

2022-07-24 14:01:53

本篇的主要程式碼依賴於之前的通用Mapper和通用Service篇

一、常用註解

在我們平時的日常開發中,會經常遇到我們的資料小夥伴們在資料庫中所建立的 表名要與我們Java開發人員所建的domian層的類名有一個對應關係,這往往在不同的公司都有著不同的要求。

打個比方:資料庫表名 t_user-------- 後臺domian的實體類名User。這樣很明顯會操做報錯。

所以我們的MyBtais-Plus為我們提供了一系列的註解,下面我們來正式學習他們

1.1 @TableName

在實體類上加上註解@TableName("t_user"),標識這個類所對應的表名是t_user,這樣才可以成功對映到對應的欄位。

@TableName("t_user")
public class User {
	private Long id;
	private String userName;
	private Integer age;
	private String email;
}

以上是通過註解的方式完成,我們也可以通過組態檔來設定

mybatis-plus:
 configuration:
  # 設定MyBatis紀錄檔
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 global-config:
  db-config:
   # 設定MyBatis-Plus操作表的預設字首
   table-prefix: t_

通過table_prefix設定字首隻適用於資料庫表有字首的,如果表名與實體類名差別甚遠,則建議使用註解

1.2 @TableId

MyBatis-Plus在實現CRUD時,會預設將id作為主鍵列,並在插入資料時,預設是基於雪花演演算法的策略生成idASSIGN_ID

【產生的問題】

  • 若實體類和表中表示主鍵的不是id,而是其他欄位 如何匹配
  • 怎樣實現資料庫中的自增策略

【對策】

在實體類中uid屬性上通過@TableId將其標識為主鍵,即可成功執行SQL語句

@TableName("t_user")
public class User {
	@TableId(value = "id", type = IdType.AUTO)
	private Long id;
	private String userName;
	private Integer age;
	private String email;
}

這裡有必要說下,idType,這個IdType是MyBatis-plus裡面所提供的一種主鍵生成策略的列舉類

【原始碼】

@Getter
public enum IdType {
    /**
     * 資料庫ID自增
     * <p>該型別請確保資料庫設定了 ID自增 否則無效</p>
     */
    AUTO(0),
    /**
     * 該型別為未設定主鍵型別(註解裡等於跟隨全域性,全域性里約等於 INPUT)
     */
    NONE(1),
    /**
     * 使用者輸入ID
     * <p>該型別可以通過自己註冊自動填充外掛進行填充</p>
     */
    INPUT(2),

    /* 以下3種型別、只有當插入物件ID 為空,才自動填充。 */
    /**
     * 分配ID (主鍵型別為number或string),
     * 預設實現類 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花演演算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主鍵型別為 string)
     * 預設實現類 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

也就是說MP提供了5種測類,下面簡要的介紹其中的某些:

  • AUTO: 資料庫自增策略,注意,該型別請確保資料庫設定了id自增, 否則無效
  • NONE:MP set主鍵,雪花演演算法實現。就是如果傳了id用傳的,否則預設的雪花演演算法
  • INPUT:需要時開發者手動賦值,沒寫一樣雪花演演算法自動生成
  • ASSIGN_ID: 雪花演演算法,預設,與資料庫id是否設定了自增無關

1.3 @TableField

TableField與TableId的區別就是:

  • TableField適用於解決非主鍵欄位不匹配的情況,而且TableField還可以指定那個欄位查詢的時候不顯示
  • TableId主要解決主鍵不匹配的情況
@TableName("t_user")
public class User {

	// 處理主鍵相關的欄位名不一致 以及設定主鍵自增策略
	@TableId(value = "id", type = IdType.AUTO)
	private Long id;

	// 在mp種預設的設定可以將資料庫中的欄位名xxx_xxx轉化為相應的駝峰命名
	@TableField(value = "user_name")
	private String userName;

	@TableField(value = "age")
	private Integer age;

	// exist=false 表示查詢時候不顯示
	@TableField(exist = false)
	private String email;
	
}

當我們使用了@TableField(exist = false)則在查詢的時候就不會顯示查詢出來的值

1.4 @TableLogic

邏輯刪除
在我們的日常開發中,會經常遇到這種邏輯刪除的操做,因為這樣仍然會在資料庫中儲存這條資料,防止後期如果還想用的話還可以找到。我們要時刻銘記,資料的CUD操做,一定要謹慎,謹慎,再謹慎!!!

如果我們的業務對資料的要求是可以恢復的,我們就要使用邏輯刪除操做,一般我們就在資料庫種加一個欄位is_deleted

  • 物理刪除:真實刪除,將對應資料從資料庫中刪除,之後查詢不到此條被刪除的資料
  • 邏輯刪除:假刪除,將對應資料中代表是否被刪除欄位的狀態修改為“被刪除狀態”,之後在資料庫中仍舊能看到此條資料記錄
  • 使用場景:可以進行資料恢復
@TableName("t_user")
public class User {

	// 處理主鍵相關的欄位名不一致 以及設定主鍵自增策略
	@TableId(value = "id", type = IdType.AUTO)
	private Long id;

	// 在mp種預設的設定可以將資料庫中的欄位名xxx_xxx轉化為相應的駝峰命名
	@TableField(value = "user_name")
	private String userName;

	@TableField(value = "age")
	private Integer age;

	@TableField(value = "email")
	private String email;
	
	// 邏輯刪除 0 標識未刪除 1表示刪除了
	@TableLogic
	private Integer isDeleted;

}

注意:當我們使用了邏輯刪除則刪除操作就變成了修改操作

測試刪除功能,真正執行的是修改

UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0

測試查詢功能,被邏輯刪除的資料預設不會被查詢

SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0

二、條件構造器Wrapper

Wrapper在MyBatis-plus裡面主要分為兩種:一種適用於查詢的 QueryWrapper;一種是用於修改的UpdateWrapper

【繼承關係】

Wrapper : 條件構造抽象類,最頂端父類別

  • AbstractWrapper : 用於查詢條件封裝,生成 sql 的 where 條件
    • QueryWrapper : 查詢條件封裝
    • UpdateWrapper : Update 條件封裝
    • AbstractLambdaWrapper : 使用Lambda 語法
      • LambdaQueryWrapper :用於Lambda語法使用的查詢Wrapper
      • LambdaUpdateWrapper : Lambda 更新封裝Wrapper

這裡主要就是介紹QueryWrapper和UpdateWrapper

2.1 QueryWrapper

上圖是BaseMapper裡面的關於引數是Warpper的方法,下面我們一一介紹:

2.1.1 組裝查詢條件selectCount

/**
	 * 測試wraper封裝查詢條件1
	 * 
	 * @throws Exception
	 */
	@Test
	public void testQuery5() {
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		// sql: SELECT COUNT( * ) FROM t_user WHERE is_deleted=0 AND (age BETWEEN ? AND
		// ?)
		queryWrapper.between("age", 18, 23);
		Long list = userMapper.selectCount(queryWrapper);
		System.out.println(list);
	}

2.1.2 組裝查詢條件selectList

/**
	 * 測試wraper封裝查詢條件2
	 * 
	 * @throws Exception
	 */
	@Test
	public void testQuery9() {
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		// SELECT id,user_name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND
		// (email IS NOT NULL AND email LIKE ?)
		queryWrapper.isNotNull("email").like("email", "163.com");
		List<User> list = userMapper.selectList(queryWrapper);
		list.forEach(System.out::println);
	}

2.1.3 組裝查詢引數selectMaps

/**
	 * 測試wraper封裝查詢條件3
	 * 
	 * @throws Exception
	 */
	@Test
	public void testQuery10() {
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		// SELECT age,email,user_name FROM t_user WHERE is_deleted=0
		queryWrapper.select("age", "email", "user_name");
		List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);
		list.forEach(System.out::println);
	}

2.1.4 組裝查詢selectOne

/**
	 * 測試wraper封裝查詢條件4
	 * 
	 * @throws Exception
	 */
	@Test
	public void testQuery11() {
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		// SELECT age,email,user_name FROM t_user WHERE is_deleted=0 AND (user_name = ?)
		queryWrapper.select("age", "email", "user_name");
		queryWrapper.eq("user_name", "test");
		User list = userMapper.selectOne(queryWrapper);
		System.out.println(list);
	}

根據上述的方法,我們可以很輕鬆地觀察到,querywrapper裡面封裝了許多的方法就是用於設定我們的查詢條件,而且比較通俗易懂,比如ge大於等於between介於等等,這裡只演示這些,剩下的自己在開發中用到繼續摸索。

2.1.5 調整條件優先順序

注意:
這裡說明下如何調整引數的優先順序,我們都知道在sql中可以通過()完成查詢條件的優先順序提升,那麼在MP中如何操做???

【程式碼演示】
通過and方法,利用lambda表示式實現

@Test
	public void testQuery7() throws Exception {
		User user = new User();
		// 將使用者名稱中包含有a並且(年齡大於20或郵箱為null)的使用者資訊修改
		user.setEmail("modifyTest@gogel.com");
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		// UPDATE t_user SET age=?, email=? WHERE (user_name LIKE ? AND (age > ? OR email IS NULL))
		queryWrapper.like("user_name", "a")
					.and(
							i -> i.ge("age", 20)
								  .or()
								  .isNull("email"));
		List<User> list = userMapper.selectList(queryWrapper);

		list.forEach(System.out::println);
	}

2.1.6 實現子查詢inSql

@GetMapping("/queryZI")
	public List<User> queryZI() {
		// SELECT id,user_name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (id IN ( SELECT id FROM t_user WHERE id <=100))
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		queryWrapper.inSql("id", " SELECT id FROM t_user WHERE id <=100");
		List<User> maps = userMapper.selectList(queryWrapper);
		return maps;
	}

2.2 UpdateWrapper

2.2.1 組裝修改條件update

@Test
	public void testUpdate2() throws Exception {
		User user = new User();
		user.setEmail("modifyTest@gogel.com");
		UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>();
		updateWrapper.ge("age", 20).like("user_name", "a").or().isNull("email");
		/**
		 * 根據 whereEntity 條件,更新記錄
		 *
		 * @param entity        實體物件 (set 條件值,可以為 null) 修改的引數
		 * @param updateWrapper 實體物件封裝操作類(可以為 null,裡面的 entity 用於生成 where 語句)條件引數
		 */
		int row = userMapper.update(user, updateWrapper);

		log.info("刪除資料={}條", row);
	}

三、MyBatis-Plus分頁外掛

MyBatis Plus自帶分頁外掛,只要簡單的設定即可實現分頁功能

3.1 實現步驟

1️⃣新增設定類

/**
 * MybatisPlus的分頁外掛設定類
 * @author wangruoxian
 *
 */
@Configuration
@MapperScan("com.wei.mapper")
public class MyBatisPlusPageConfig {
	@Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() {
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
		return interceptor;
	}
}

2️⃣ 測試

@GetMapping("/page")
	public IPage<User> pageList(){
		Page<User> page = new Page<User>(1,3);
//		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
//		// 當前頁碼
//		page.setCurrent(1);
//		// 每頁顯示的條數
//		page.setSize(5);
		IPage<User> selectPage = userMapper.selectPage(page, null);
		log.info("當前頁數={}",selectPage.getCurrent());
		log.info("總頁數={}",selectPage.getPages());
		selectPage.getRecords().forEach(System.out::println);
		log.info("每頁大小={}",selectPage.getSize());
		log.info("總資料條數={}",selectPage.getTotal());
		return selectPage;
	}

四、通用列舉

表中的有些欄位值是固定的,例如性別(男或女),此時我們可以使用MyBatis-Plus的通用列舉來實現

4.1 資料庫表新增欄位sex

4.2 設定掃描通用列舉

# 設定掃描通用列舉
type-enums-package: com.wei.enums

4.3 新建列舉類

@Getter
public enum SexEnum {
	MALE(0,"男"),
	FEMALE(1,"女");
	
	@EnumValue
	private Integer sexCode;
	
	private String sexValue;
	
	private SexEnum(Integer sexCode, String sexValue) {
		this.sexCode = sexCode;
		this.sexValue = sexValue;
	}
}

4.3.1 @EnumValue註解

通用的列舉類註解,將資料庫欄位對映成實體類的列舉型別成員變數

將列舉改成成員變數和資料庫的欄位對映起來,根據資料庫欄位的值找到對應列舉的物件

4.4 測試

五、多資料來源

適用於多種場景:純粹多庫、 讀寫分離、 一主多從、 混合模式等,目前我們就來模擬一個純粹多庫的一個場景,其他場景類似

場景說明:
我們建立兩個庫,分別為:mybatis_plus(以前的庫不動)與mybatis_plus_1(新建),將
mybatis_plus庫的product表移動到mybatis_plus_1庫,這樣每個庫一張表,通過一個測試用例
分別獲取使用者資料與商品資料,如果獲取到說明多庫模擬成功

5.1 建立資料庫及表

CREATE DATABASE `mybatis_plus_slave` 
use `mybatis_plus_slave`;

CREATE TABLE t_product
(
id BIGINT(20) NOT NULL COMMENT '主鍵ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名稱',
price INT(11) DEFAULT 0 COMMENT '價格',
version INT(11) DEFAULT 0 COMMENT '樂觀鎖版本號',
PRIMARY KEY (id)
);

INSERT INTO product (id, NAME, price) VALUES (1, '外星人筆電', 100);

5.2 引入依賴

<!-- 引入依賴 多資料來源 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
			<version>3.3.1</version>
		</dependency>

5.3 設定多資料來源

注意 註釋掉之前的設定 ,也可以新建一個專案進行測試

spring:
 # 設定資料來源資訊
 datasource:
  dynamic:
   # 設定預設的資料來源或者資料來源組,預設值即為master
   primary: master
   # 嚴格匹配資料來源,預設false.true未匹配到指定資料來源時拋異常,false使用預設資料來源
   strict: false
   datasource:
    master:
     url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
     driver-class-name: com.mysql.cj.jdbc.Driver
     username: root
     password: 123456
    slave_1:
     url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
     driver-class-name: com.mysql.cj.jdbc.Driver
     username: root
     password: 123456

5.4 建立新庫中Product對應的類

此處省略domain,mapper,service,serviceImpl的建立
【controller層】

@RestController
@RequestMapping("/product")
@Api(value = "測試 ProductController 的介面", tags = "產品管理相關的介面", description = "product產品測試介面")
public class ProductController {
	
	@Autowired
	private IProductService IProductService;

	@GetMapping("/list")
//	@ApiOperation("查詢所有商品的介面")
	public List<Product> queryAllProduct(){
		return IProductService.list();
	}
}

 到此這篇關於MyBatis-Plus 條件查詢器的實現的文章就介紹到這了,更多相關MyBatis-Plus 條件查詢器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com