javascript
MyBatis_Plus(Spring版本笔记)
目錄
- 前言
- 一、MyBatis-Plus簡介
- 1.1 簡介
- 1.2 特性
- 1.3 支持數據庫
- 1.4 框架結構
- 1.5 代碼及文檔地址
- 二、 入門案例
- 2.1 開發環境
- 2.2 創建數據庫和表
- 2.2.1 創建表
- 2.2.2 添加數據
- 2.3 創建maven工程
- 2.3.1 打包方式 jar
- 2.3.2 引入依賴
- 2.4 Spring整合MyBatis
- 2.4.1 創建實體
- 2.4.2 創建MyBatis的核心配置文件
- 2.4.3 創建mapper接口和映射文件
- 2.4.4 創建jdbc.properties
- 2.4.5 創建Spring的配置文件
- 2.4.6 添加日志功能
- 2.4.7 測試
- 2.5 加入MyBatis-Plus
- 2.5.1 創建Mapper接口
- 2.5.2 測試
- 2.5.3 結果
- 2.6 總結
- 三、基本CRUD
- 3.1 BaseMapper
- 3.2 BaseMapper功能測試
- 3.3 通用Service
- 3.3.1 IService
- 3.3.2 創建Service接口和實現類
- 3.3.3 在spring配置文件中設置自動掃描service的包
- 3.3.4 測試查詢記錄條數和批量添加
- 四、常用注解
- 4.1 @TableName
- 4.1.1 問題
- 4.1.2 通過@TableName解決問題
- 4.1.3 通過GlobalConfig解決問題
- 4.2 @TableId
- 4.2.1 問題引出
- 4.2.2 通過@TableId解決問題
- 4.2.3 @TableId的value屬性
- 4.2.4 @TableId的type屬性
- 4.2.5 雪花算法
- 4.3 @TableField
- 4.4 @TableLogic(邏輯刪除)
- 4.4.1 邏輯刪除
- 4.4.2 實現邏輯刪除
- 五、條件構造器和常用接口
- 5.1 wapper介紹
- 5.2 QueryWrapper
- 5.2.1 組裝查詢條件
- 5.2.2 組裝排序條件
- 5.2.3 組裝刪除條件
- 5.2.4 條件的優先級
- 5.2.5 組裝select子句
- 5.2.6 實現子查詢
- 5.3 UpdateWrapper
- 5.4 condition
- 5.5 LambdaQueryWrapper
- 5.6 LambdaUpdateWrapper
- 六、插件
- 6.1 分頁插件
- 6.1.1 添加配置
- 6.1.2 測試
- 6.2 xml自定義分頁
- 6.2.1 UserMapper中定義接口方法
- 6.2.2 UserMapper.xml中編寫SQL
- 6.2.3 測試
- 6.3 樂觀鎖
- 6.3.1 場景
- 6.3.2 樂觀鎖與悲觀鎖
- 6.3.3 模擬修改沖突
- 6.3.4 樂觀鎖實現流程
- 6.3.5 Mybatis-Plus實現樂觀鎖
- 七 、通用枚舉
- 7.1 數據庫添加字段sex
- 7.2 創建通用枚舉
- 7.3 配置掃描通用枚舉
- 7.4 測試
- 八、代碼生成器
- 8.1 引入依賴
- 8.2 快速生成
- 九 、MyBatisX插件
- 9.1 安裝插件
- 9.2 功能
- 9.2.1 XML跳轉
- 9.2.2 快速生成代碼
- 十、總結
前言
本文主要參考嗶站尚硅谷楊博超講師課件整理而成,屬于自己復習使用。
提示:以下是本篇文章正文內容,下面案例可供參考
一、MyBatis-Plus簡介
1.1 簡介
MyBatis-Plus(簡稱 MP)是一個 MyBatis的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。
愿景
我們的愿景是成為 MyBatis 最好的搭檔,就像魂斗羅中的 1P、2P,基友搭配,效率翻倍。
1.2 特性
- 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑
- 損耗小:啟動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作
- 強大的 CRUD 操作:內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求
- 支持 Lambda 形式調用:通過 Lambda 表達式,方便的編寫各類查詢條件,無需再擔心字段寫錯
- 支持主鍵自動生成:支持多達 4 種主鍵策略(內含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可進行強大的 CRUD 操作
- 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 內置代碼生成器:采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用
- 內置分頁插件:基于 MyBatis 物理分頁,開發者無需關心具體操作,配 插件之后,寫分頁等同于普通 List 查詢
- 分頁插件支持多種數據庫:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數據庫
- 內置性能分析插件:可輸出 SQL 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢
1.3 支持數據庫
任何能使用MyBatis進行 CRUD, 并且支持標準 SQL 的數據庫,具體支持情況如下
- MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQLSQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
- 達夢數據庫,虛谷數據庫,人大金倉數據庫,南大通用(華庫)數據庫,南大通用數據庫,神通數據庫,瀚高數據庫
1.4 框架結構
1.5 代碼及文檔地址
官方地址:http://mp.baomidou.com
代碼發布地址:
Github: https://github.com/baomidou/mybatis-plus
Gitee: https://gitee.com/baomidou/mybatis-plus
文檔發布地址:https://baomidou.com/pages/24112f
二、 入門案例
2.1 開發環境
以maven工程為例,以ssm整合為技術框架。
| IDE | idea 2021.3 |
| JDK | JDK1.8 |
| MAVEN | maven 3.8.4 |
| MySQL | MySQL8.0.25 |
| Spring | 5.3.1 |
| MyBatis-Plus | 3.4.3.4 |
2.2 創建數據庫和表
2.2.1 創建表
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL COMMENT '主鍵ID', `name` varchar(30) DEFAULT NULL COMMENT '姓名', `age` int(11) DEFAULT NULL COMMENT '年齡', `email` varchar(50) DEFAULT NULL COMMENT '郵箱', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;2.2.2 添加數據
INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');2.3 創建maven工程
2.3.1 打包方式 jar
<packaging>jar</packaging>2.3.2 引入依賴
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!-- 連接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!-- junit測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!-- lombok用來簡化實體類 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--MyBatis-Plus的核心依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.4.3.4</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency></dependencies><properties><spring.version>5.3.1</spring.version></properties>注意:
Spring整合MyBatis,需要MyBatis以及Spring整合MyBatis的依賴:
但是,在以上的依賴列表中,并沒有MyBatis以及Spring整合MyBatis的依賴,因為當我們引入了
MyBatis-Plus的依賴時,就可以間接的引入這些依賴
并且依賴和依賴之間的版本必須兼容,所以我們不能隨便引入其他版本的依賴,以免發生沖突
在官網上有明確提示:
2.4 Spring整合MyBatis
2.4.1 創建實體
public class User {private Long id;private String name;private int age;private String email;public User(Long id, String name, int age, String email) {this.id = id;this.name = name;this.age = age;this.email = email;}public User() {}public Long getId() {return this.id;}public String getName() {return this.name;}public int getAge() {return this.age;}public String getEmail() {return this.email;}public SexEnum getSex() {return this.sex;}public int getIsDeleted() {return this.isDeleted;}public void setId(Long id) {this.id = id;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setEmail(String email) {this.email = email;}public void setSex(SexEnum sex) {this.sex = sex;}public void setIsDeleted(int isDeleted) {this.isDeleted = isDeleted;}public String toString() {return "User(id=" + this.getId() + ", name=" + this.getName() + ", age=" + this.getAge() + ", email=" + this.getEmail() + ", sex=" + this.getSex() + ", isDeleted=" + this.getIsDeleted() + ")";} }2.4.2 創建MyBatis的核心配置文件
在resources下創建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration></configuration>2.4.3 創建mapper接口和映射文件
- mapper接口:
- mapper映射文件:
在resources下的com/atguigu/mp/mapper目錄下創建TestMapper.xml
2.4.4 創建jdbc.properties
在resources下創建jdbc.properties
jdbc.username=root jdbc.password=5864@WCY jdbc.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false jdbc.driver=com.mysql.cj.jdbc.Driver2.4.5 創建Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- 引入jdbc.properties --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Druid數據源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置用于創建SqlSessionFactory的工廠bean --><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!-- 設置MyBatis配置文件的路徑(可以不設置) --><property name="configLocation" value="classpath:mybatis-config.xml"></property><!-- 設置數據源 --><property name="dataSource" ref="dataSource"></property><!-- 設置類型別名所對應的包 --><property name="typeAliasesPackage" value="com.atguigu.mybatisplus.pojo"></property><!--設置映射文件的路徑若映射文件所在路徑和mapper接口所在路徑一致,則不需要設置--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/></bean><!--配置mapper接口的掃描配置由mybatis-spring提供,可以將指定包下所有的mapper接口創建動態代理并將這些動態代理作為IOC容器的bean管理--><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.atguigu.mybatisplus.mapper"></property></bean><!--配置自動掃描的包--><context:component-scan base-package="com.atguigu.mybatisplus.service"></context:component-scan> </beans>2.4.6 添加日志功能
在resources下創建logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"><!--定義日志文件的存儲地址 logs為當前項目的logs目錄 還可以設置為../logs --><property name="LOG_HOME" value="logs" /><!--控制臺日志, 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度,%msg:日志消息,%n是換行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n</pattern></encoder></appender><!--myibatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志輸出級別 --><root level="DEBUG"><appender-ref ref="STDOUT" /></root></configuration>2.4.7 測試
- 方式一:通過IOC容器
- 方式二 Spring整合junit
2.5 加入MyBatis-Plus
Spring整合MyBatis
加入MyBatis-Plus之后
此處使用的是MybatisSqlSessionFactoryBean
經觀察,目前bean中配置的屬性和SqlSessionFactoryBean一致
MybatisSqlSessionFactoryBean是在SqlSessionFactoryBean的基礎上進行了增強
即具有SqlSessionFactoryBean的基礎功能,又具有MyBatis-Plus的擴展配置
具體配置信息地址(https://baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%
85%8D%E7%BD%AE)
2.5.1 創建Mapper接口
public interface UserMapper extends BaseMapper<User> { }BaseMapper是MyBatis-Plus提供的基礎mapper接口,泛型為所操作的實體類型,其中包含CRUD的各個方法,我們的mapper繼承了BaseMapper之后,就可以直接使用BaseMapper所提供的各種方法,而不需要編寫映射文件以及SQL語句,大大的提高了開發效率
2.5.2 測試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusTest {/*沒有使用mybatis_plus@Testpublic void testMyBatis(){ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");UserMapper mapper = ac.getBean(UserMapper.class);mapper.getAllUser().forEach(user -> System.out.println(user));}*/@Autowiredprivate UserMapper userMapper;/*---------------------------------使用MyBatisPlus之后-------------------------------------*/@Testpublic void testMyBatisPlus(){//查詢所有用戶信息// SELECT id,name,age,email FROM userSystem.out.println(userMapper.selectList(null));}2.5.3 結果
2.6 總結
在Spring整合MyBatis中加入了MyBatis-Plus后,我們就可以使用MyBatis-Plus所提供的BaseMapper實現CRUD,并不需要編寫映射文件以及SQL語句
但是若要自定義SQL語句,仍然可以編寫映射文件而不造成任何影響。因為MyBatis-Plus只做增強,而不做改變。
三、基本CRUD
3.1 BaseMapper
MyBatis-Plus中的基本CRUD在內置的BaseMapper中都已得到了實現,我們可以直接使用,接口如下:
/*** Mapper 繼承該接口后,無需編寫 mapper.xml 文件,即可獲得CRUD功能* <p>這個 Mapper 支持 id 泛型</p>** @author hubin* @since 2016-01-23*/ public interface BaseMapper<T> extends Mapper<T> {/*** 插入一條記錄** @param entity 實體對象*/int insert(T entity);/*** 根據 ID 刪除** @param id 主鍵ID*/int deleteById(Serializable id);/*** 根據實體(ID)刪除** @param entity 實體對象* @since 3.4.4*/int deleteById(T entity);/*** 根據 columnMap 條件,刪除記錄** @param columnMap 表字段 map 對象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據 entity 條件,刪除記錄** @param queryWrapper 實體對象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 刪除(根據ID 批量刪除)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根據 ID 修改** @param entity 實體對象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根據 whereEntity 條件,更新記錄** @param entity 實體對象 (set 條件值,可以為 null)* @param updateWrapper 實體對象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根據 ID 查詢** @param id 主鍵ID*/T selectById(Serializable id);/*** 查詢(根據ID 批量查詢)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查詢(根據 columnMap 條件)** @param columnMap 表字段 map 對象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據 entity 條件,查詢一條記錄* <p>查詢一條記錄,例如 qw.last("limit 1") 限制取一條記錄, 注意:多條數據會報異常</p>** @param queryWrapper 實體對象封裝操作類(可以為 null)*/default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {List<T> ts = this.selectList(queryWrapper);if (CollectionUtils.isNotEmpty(ts)) {if (ts.size() != 1) {throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");}return ts.get(0);}return null;}/*** 根據 Wrapper 條件,查詢總記錄數** @param queryWrapper 實體對象封裝操作類(可以為 null)*/Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 entity 條件,查詢全部記錄** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄* <p>注意: 只返回第一個字段的值</p>** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 entity 條件,查詢全部記錄(并翻頁)** @param page 分頁查詢條件(可以為 RowBounds.DEFAULT)* @param queryWrapper 實體對象封裝操作類(可以為 null)*/<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄(并翻頁)** @param page 分頁查詢條件* @param queryWrapper 實體對象封裝操作類*/<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); }3.2 BaseMapper功能測試
//插入@Testpublic void testInsert(){// INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )User user = new User(6,"張三",23,"zhangsan@126.com");int result = userMapper.insert(user);System.out.println("result="+result);}//刪除@Testpublic void testDelete(){//根據Id刪除用戶//DELETE FROM user WHERE id=?int result = userMapper.deleteById(2L);//根據map集合刪除//DELETE FROM user WHERE name = ? AND age = ?Map<String,Object> map = new HashMap<>();map.put("name","張三");map.put("age",23);int result = userMapper.deleteByMap(map);// 根據id批量刪除// DELETE FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 3);int result = userMapper.deleteBatchIds(list);System.out.println("result="+result);}//修改@Testpublic void testUpdate(){ // UPDATE user SET name=?, email=? WHERE id=?User user = new User();user.setId(4L);user.setName("李四");user.setEmail("lisi@atguigu.com");int result = userMapper.updateById(user);System.out.println("result="+result);}//查詢@Testpublic void testSelect(){//根據Id查詢用戶 // SELECT id,name,age,email FROM user WHERE id=?User user = userMapper.selectById(5L);System.out.println(user);// SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 4);List<User> users = userMapper.selectBatchIds(list);users.forEach(System.out::println);Map<String,Object> map = new HashMap<>();map.put("age",23);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);}通過觀察BaseMapper中的方法,大多方法中都有Wrapper類型的形參,此為條件構造器,可針對于SQL語句設置不同的條件,若沒有條件,則可以為該形參賦值null,即查詢(刪除/修改)所有數據
3.3 通用Service
說明:
- 通用 Service CRUD 封裝IService接口,進一步封裝 CRUD 采用 get 查詢單行 remove 刪除 list 查詢集合 page 分頁 , 前綴命名方式區分 Mapper 層避免混淆
- 泛型 T 為任意實體對象
- 建議如果存在自定義通用 Service 方法的可能,請創建自己的 IBaseService 繼承Mybatis-Plus 提供的基類
- 官網地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3
3.3.1 IService
MyBatis-Plus中有一個接口 IService和其實現類 ServiceImpl,封裝了常見的業務層邏輯
詳情查看源碼IService和ServiceImpl
3.3.2 創建Service接口和實現類
UserService
/** * UserService繼承IService模板提供的基礎功能 */ public interface UserService extends IService<User> {}UserServiceImpl
/** * ServiceImpl實現了IService,提供了IService中基礎功能的實現 * 若ServiceImpl無法滿足業務需求,則可以使用自定的UserService定義方法,并在實現類中實現 */ @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}3.3.3 在spring配置文件中設置自動掃描service的包
在applicationContext.xml中添加掃描組件的配置,掃描業務層組件,用于測試
<context:component-scan base-package="com.atguigu.mybatisplus.service.impl"></context:component-scan>3.3.4 測試查詢記錄條數和批量添加
//spring測試類寫法一 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisServiceTest {@Autowiredprivate UserService userService;@Testpublic void testCount(){//查詢總記錄條數//SELECT COUNT( * ) FROM userlong count = userService.count();System.out.println("總記錄條數" + count);}@Testpublic void testSaveBatch(){//實現新增用戶ArrayList<User> list = new ArrayList<>();// SQL長度有限制,海量數據插入單條SQL無法實行,// 因此MP將批量插入放在了通用Service中實現,而不是通用Mapperfor (int i = 0; i < 100 ; i++) {User user = new User();user.setName("abc"+i);user.setAge(20+i);list.add(user);}//INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )boolean b = userService.saveBatch(list);System.out.println(b);}}錯誤:
Duplicate entry ‘0’ for key ‘PRIMARY’
原因:發現了是數據庫表設計不合理導致的;
因為主鍵設置不能為空,因此默認是以"0"來進行填充的。因此在數據插入時數據的主鍵id值被0占據,但由于之前已經有數據了,id為“0”的索引已經被占,在使用就會報這個錯誤,因此我們只需要對表中的主鍵“id”設置成自增即可。
糾正:為什么會出現這個問題,是因為在創建實體類的時候id屬性的類型寫成long了,應該寫成Long,不然雪花算法是不會實現的。大小寫要注意。
四、常用注解
4.1 @TableName
經過以上的測試,在使用MyBatis-Plus實現基本的CRUD時,我們并沒有指定要操作的表,只是在Mapper接口繼承BaseMapper時,設置了泛型User,而操作的表為user表:
由此得出結論,MyBatis-Plus在確定操作的表時,由BaseMapper的泛型決定,即實體類型決定,且默認操作的表名和實體類型的類名一致
4.1.1 問題
若實體類類型的類名和要操作的表的表名不一致,會出現什么問題?
我們將表user更名為t_user,測試查詢功能
程序拋出異常,Table ‘mybatis_plus.user’ doesn’t exist,因為現在的表名為t_user,而默認操作的表名和實體類型的類名一致,即user表
4.1.2 通過@TableName解決問題
在實體類類型上添加==@TableName(“t_user”)==,標識實體類對應的表,即可成功執行SQL語句。
4.1.3 通過GlobalConfig解決問題
在開發的過程中,我們經常遇到以上的問題,即實體類所對應的表都有固定的前綴,例如t_或tbl_
此時,可以使用MyBatis-Plus提供的全局配置,為實體類所對應的表名設置默認的前綴,那么就不需要在每個實體類上通過@TableName標識實體類對應的表。
在spring配置文件中修改:spring-persist.xml中的sqlsessionfactorybean
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property></bean><bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean id="config" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!--設置實體類所對應的表的前綴--><property name="tablePrefix" value="t_"></property></bean></property></bean>4.2 @TableId
經過以上的測試,MyBatis-Plus在實現CRUD時,會默認將id作為主鍵列,并在插入數據時,默認基于雪花算法的策略生成id。
4.2.1 問題引出
若實體類和表中表示主鍵的不是id,而是其他字段,例如uid,MyBatis-Plus會自動識別uid為主鍵列嗎?
我們實體類中的屬性id改為uid,將表中的字段id也改為uid,測試添加功能程序拋出異常,Field ‘uid’ doesn’t have a default value,說明MyBatis-Plus沒有將uid作為主鍵賦值
4.2.2 通過@TableId解決問題
在實體類中uid屬性上通過@TableId將其標識為主鍵,即可成功執行SQL語句。
4.2.3 @TableId的value屬性
若實體類中主鍵對應的屬性為id,而表中表示主鍵的字段為uid,此時若只在屬性id上添加注解@TableId,則拋出異常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然會將id作為表的主鍵操作,而表中表示主鍵的是字段uid
此時需要通過@TableId注解的value屬性,指定表中的主鍵字段@TableId(“uid”)或@TableId(value=“uid”)
4.2.4 @TableId的type屬性
type屬性用來定義主鍵策略
[1]臨時修改
[2] 配置全局配置(全局有效)
在spring-persist.xml中修改。
4.2.5 雪花算法
4.3 @TableField
經過以上的測試,我們可以發現,MyBatis-Plus在執行SQL語句時,要保證實體類中的屬性名和表中的字段名一致
如果實體類中的屬性名和字段名不一致的情況,會出現什么問題呢?
a>情況1
若實體類中的屬性使用的是駝峰命名風格,而表中的字段使用的是下劃線命名風格
例如實體類屬性userName,表中字段user_name
此時MyBatis-Plus會自動將下劃線命名風格轉化為駝峰命名風格
相當于在MyBatis中配置
b>情況2
若實體類中的屬性和表中的字段不滿足情況1
例如實體類屬性name,表中字段username
此時需要在實體類屬性上使用@TableField(“username”)設置屬性所對應的字段名
4.4 @TableLogic(邏輯刪除)
4.4.1 邏輯刪除
邏輯刪除
物理刪除:真實刪除,將對應數據從數據庫中刪除,之后查詢不到此條被刪除的數據
邏輯刪除:假刪除,將對應數據中代表是否被刪除字段的狀態修改為“被刪除狀態”,之后在數據庫中仍舊能看到此條數據記錄
使用場景:可以進行數據恢復
4.4.2 實現邏輯刪除
數據庫中創建邏輯刪除狀態列,設置默認值為0
實體類中添加邏輯刪除屬性
- 測試刪除功能,真正執行的是修改
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
五、條件構造器和常用接口
5.1 wapper介紹
5.2 QueryWrapper
5.2.1 組裝查詢條件
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusWrapperTest {@Autowiredpublic UserMapper userMapper;@Testpublic void test01(){//查詢用戶名包含a,年齡在20到30之間,并且郵箱不為null的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)queryWrapper.like("user_name","a").between("age",20,30).isNotNull("email");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.2 組裝排序條件
@Testpublic void test02(){//按年齡降序查詢用戶,如果年齡相同則按id升序排列//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASCQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.3 組裝刪除條件
@Testpublic void test03(){//刪除email為空的用戶QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)//出現這個是因為我們設置了邏輯刪除,即刪除變成了修改,將狀態從0(未刪除狀態)--->1(已刪除狀態);queryWrapper.isNull("email");int result = userMapper.delete(queryWrapper);System.out.println("受影響的行數 : " + result);}5.2.4 條件的優先級
/*** update(User entity,Wrapper<User> updateWrapper)* 第一個參數為修改的內容,第二個參數為設置修改的條件參數1設置修改的字段和值,參數2是查詢符合的條件**/@Testpublic void test04(){//條件包裝器中條件之間默認是and連接。我們不需要手動設置,但是如果是或,我們需要手動設置or.//將(年齡大于20并且用戶名中包含有a)或郵箱為null的用戶信息修改QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET user_name=?, age=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND age > ? OR email IS NULL)queryWrapper.like("user_name","a").gt("age",20).or().isNull("email");User user = new User();user.setName("小明");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影響的行數:" + result);} @Testpublic void test05(){//將(年齡大于20或郵箱為null)并且用戶名中包含有a的用戶信息修改//lambda表達式內的邏輯優先運算QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))queryWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.5 組裝select子句
@Testpublic void test06(){//查詢用戶信息的username和age字段QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT user_name,age FROM t_user WHERE is_deleted=0queryWrapper.select("user_name","age");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}5.2.6 實現子查詢
@Testpublic void test07(){//查詢id小于等于3的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 3))queryWrapper.inSql("uid","select uid from t_user where uid <= 3");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.3 UpdateWrapper
@Testpublic void test08(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();/*寫在一起updateWrapper.set("age",18).set("email","user@atguigu.com").like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));*///分開寫//UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))updateWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));updateWrapper.set("user_name","小黑").set("email","abc@atguigu.xom");//這里必須要創建User對象,否則無法應用自動填充。如果沒有自動填充,可以設置為null//UPDATE t_user SET username=?, age=?,email=? WHERE (username LIKE ? AND(age > ? OR email IS NULL))//User user = new User();//user.setName("張三");//int result = userMapper.update(user, updateWrapper);//UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? ORemail IS NULL))int result = userMapper.update(null, updateWrapper);System.out.println("result = " + result);}5.4 condition
在真正開發的過程中,組裝條件是常見的功能,而這些條件數據來源于用戶輸入,是可選的,因此我們在組裝這些條件時,必須先判斷用戶是否選擇了這些條件,若選擇則需要組裝該條件,若沒有選擇則一定不能組裝,以免影響SQL執行的結果。
思路一:
@Testpublic void test09(){//定義查詢條件,有可能為null(用戶未輸入或未選擇)String username = null;Integer ageBegin = 20;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)//StringUtils.isNotBlank()判斷某字符串是否不為空且長度不為0且不由空白符(whitespace)構成if(StringUtils.isNotBlank(username)){queryWrapper.like("user_name","a");}if (ageBegin != null){queryWrapper.ge("age",ageBegin);}if (ageEnd != null){queryWrapper.le("age",ageEnd);}List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}思路2:
上面的實現方案沒有問題,但是代碼比較復雜,我們可以使用帶condition參數的重載方法構建查詢條件,簡化代碼的編寫
@Testpublic void test10(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),"user_name","a").ge(ageBegin != null,"age",ageBegin).le(ageEnd != null,"age",ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}5.5 LambdaQueryWrapper
@Testpublic void test11(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),User::getName,"a").ge(ageBegin != null,User::getAge,ageBegin).le(ageEnd != null,User::getAge,ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}5.6 LambdaUpdateWrapper
@Testpublic void test12(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();/*合在一起updateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));*///分開寫updateWrapper.like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));updateWrapper.set(User::getName,"小黑").set(User::getEmail,"abc@atguigu.com");User user = new User();int result = userMapper.update(user, updateWrapper);System.out.println("受影響的行數:" + result);}六、插件
6.1 分頁插件
MyBatis Plus自帶分頁插件,只要簡單的配置即可實現分頁功能。
6.1.1 添加配置
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean><!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref></list></property></bean><!--配置Mybatis-plus分頁插件的bean--><bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"><!--設置數據庫類型--><property name="dbType" value="MYSQL"></property></bean>6.1.2 測試
@Testpublic void testPage(){//設置分頁參數Page<User> page = new Page<>(2,3);userMapper.selectPage(page,null);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數:"+page.getSize());System.out.println("總記錄數:"+page.getTotal());System.out.println("總頁數:"+page.getPages());System.out.println( "當前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}測試結果:
User(id=1, name=Jone, age=18, email=test1@baomidou.com, isDeleted=0) User(id=2,name=Jack, age=20, email=test2@baomidou.com, isDeleted=0) User(id=3, name=Tom,age=28, email=test3@baomidou.com, isDeleted=0) User(id=4, name=Sandy, age=21,email=test4@baomidou.com, isDeleted=0) User(id=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=0) 當前頁:1 每頁顯示的條數:5 總記錄數:17 總頁數:4 是否有上一
頁:false 是否有下一頁:true
6.2 xml自定義分頁
6.2.1 UserMapper中定義接口方法
/*** 根據年齡查詢用戶列表,分頁顯示* @param page 分頁對象,xml中可以從里面進行取值,傳遞參數 Page 即自動分頁,必須放在第一位* @param age 年齡* @return*/IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);}6.2.2 UserMapper.xml中編寫SQL
<!--IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);--><select id="selectPageVo" resultType="User">select uid,user_name,age,email from t_user where age > #{age}</select>6.2.3 測試
@Testpublic void testPageVo(){Page<User> page = new Page<>(1,5);//第一頁索引為1,不是0userMapper.selectPageVo(page,20);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數:"+page.getSize());System.out.println("總記錄數:"+page.getTotal());System.out.println("總頁數:"+page.getPages());System.out.println( "當前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}結果:
User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=null)
User(id=4,name=Sandy, age=21,email=test4@baomidou.com, isDeleted=null) User(id=5, name=Billie,age=24, email=test5@baomidou.com, isDeleted=null) User(id=8,name=ybc1, age=21,email=null, isDeleted=null)
User(id=9, name=ybc2, age=22,email=null, isDeleted=null)
當前頁:1 每頁顯示的條數:5 總記錄數:12 總頁數:3 是否有上一頁:false 是否有下一頁:true
6.3 樂觀鎖
6.3.1 場景
一件商品,成本價是80元,售價是100元。老板先是通知小李,說你去把商品價格增加50元。小李正在玩游戲,耽擱了一個小時。正好一個小時后,老板覺得商品價格增加到150元,價格太高,可能會影響銷量。又通知小王,你把商品價格降低30元。
此時,小李和小王同時操作商品后臺系統。小李操作的時候,系統先取出商品價格100元;小王也在操作,取出的商品價格也是100元。小李將價格加了50元,并將100+50=150元存入了數據
庫;小王將商品減了30元,并將100-30=70元存入了數據庫。是的,如果沒有鎖,小李的操作就完全被小王的覆蓋了。
現在商品價格是70元,比成本價低10元。幾分鐘后,這個商品很快出售了1千多件商品,老板虧1萬多。
6.3.2 樂觀鎖與悲觀鎖
上面的故事,如果是樂觀鎖,小王保存價格前,會檢查下價格是否被人修改過了。如果被修改過了,則重新取出的被修改后的價格,150元,這樣他會將120元存入數據庫。
如果是悲觀鎖,小李取出數據后,小王只能等小李操作完之后,才能對價格進行操作,也會保證最終的價格是120元。
6.3.3 模擬修改沖突
a>數據庫中增加商品表
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) );b>添加數據
INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人筆記本', 100);c>添加實體
*/@Data public class Product {private Long id;private String name;private Integer price;}d>添加mapper
public interface ProductMapper extends BaseMapper<Product> {}f>測試
@Testpublic void testProduct01(){//小李查詢價格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價格:" + productLi.getPrice());//小王查詢價格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價格:" + productWang.getPrice());//小李將商品價格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);//老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價格為:" + productBoss.getPrice());}6.3.4 樂觀鎖實現流程
數據庫中添加version字段
取出記錄時,獲取當前version
更新時,version + 1,如果where語句中的version版本不對,則更新失敗
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=16.3.5 Mybatis-Plus實現樂觀鎖
[1]修改實體類
*/@Data public class Product {private Long id;private String name;private Integer price;@Versionprivate Integer version;}[2]添加樂觀鎖插件配置
<!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref><ref bean="optimisticLockerInnerInterceptor"></ref></list></property></bean><!--配置樂觀鎖插件--><bean id="optimisticLockerInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor"></bean>[3] 測試修改沖突
小李查詢商品信息:
SELECT id,name,price,version FROM t_product WHERE id=?
小王查詢商品信息:
SELECT id,name,price,version FROM t_product WHERE id=?
小李修改商品價格,自動將version+1
UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人筆記本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
小王修改商品價格,此時version已更新,條件不成立,修改失敗
UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人筆記本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
最終,小王修改失敗,查詢價格:150
SELECT id,name,price,version FROM t_product WHERE id=?
[4]優化流程
@Testpublic void testProduct01(){//小李查詢價格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價格:" + productLi.getPrice());//小王查詢價格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價格:" + productWang.getPrice());//小李將商品價格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價格-30productWang.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);}//老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價格為:" + productBoss.getPrice());}七 、通用枚舉
表中的有些字段值是固定的,例如性別(男或女),此時我們可以使用MyBatis-Plus的通用枚舉來實現。
7.1 數據庫添加字段sex
7.2 創建通用枚舉
*/@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;} }7.3 配置掃描通用枚舉
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置掃描通用枚舉--><property name="typeEnumsPackage" value="com.atguigu.mybatisplus.enums"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean>7.4 測試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusEnumTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSexEnum(){User user = new User();user.setName("Enum");user.setAge(20);//設置性別信息為枚舉項,會將@EnumValue注解所標識的屬性值存儲到數據庫// INSERT INTO t_user ( user_name, age, sex, is_deleted ) VALUES ( ?, ?, ?, ? )user.setSex(SexEnum.MALE);userMapper.insert(user);}八、代碼生成器
8.1 引入依賴
<!--代碼生成器逆向工程依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><!--代碼生成器中 freemarker引擎模板需要這個依賴--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>8.2 快速生成
public class FastAutoGeneratorTest {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false","root", "5864@WCY").globalConfig(builder -> {builder.author("atguigu") // 設置作者// .enableSwagger() // 開啟 swagger 模式.fileOverride() // 覆蓋已生成文件.outputDir("F://JAVA listen//code//mybatis_plus"); // 指定輸出目錄}).packageConfig(builder -> {builder.parent("com.atguigu") // 設置父包名.moduleName("mybatisplus") // 設置父包模塊名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F://JAVA listen//code//mybatis_plus"));// 設置mapperXml生成路徑}).strategyConfig(builder -> {builder.addInclude("t_user") // 設置需要生成的表名.addTablePrefix("t_", "c_"); // 設置過濾表前綴}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默認的是Velocity引擎模板.execute();}}九 、MyBatisX插件
MyBatis-Plus為我們提供了強大的mapper和service模板,能夠大大的提高開發效率。
但是在真正開發過程中,MyBatis-Plus并不能為我們解決所有問題,例如一些復雜的SQL,多表聯查,我們就需要自己去編寫代碼和SQL語句,我們該如何快速的解決這個問題呢,這個時候可以使用MyBatisX插件。
MyBatisX一款基于 IDEA 的快速開發插件,為效率而生。
MyBatisX插件用法:https://baomidou.com/pages/ba5b24/
9.1 安裝插件
安裝方法:打開 IDEA,進入 File -> Settings -> Plugins -> Browse Repositories,輸入 mybatisx 搜索并安裝
9.2 功能
9.2.1 XML跳轉
當mapper映射文件和mapper很多的時候,可以快速定位并跳轉到對應的類容上。
9.2.2 快速生成代碼
[1]首先需要在datasource中進行配置
[2] 選擇驅動
[3]可以直接選擇舊版本的驅動,或者按提示下載
[4] 登錄后選擇數據庫、表,然后點擊右鍵選擇mybatisx。
[5] 表的基本配置
[6] 生成的基本配置
[7]選擇好后會自動幫我們生成各種組件
[8]如果我們要自定義查詢功能,我們只需要在mapper中寫我們的方法名,插件會自動幫助我們補全方法名并且快速生成相對應的sql語句放在mapper映射文件中。
十、總結
mybatsi-plus可以快速幫助我們完成spring和mybatsi的整合及搭建功能。
總結
以上是生活随笔為你收集整理的MyBatis_Plus(Spring版本笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker从入门到放弃------do
- 下一篇: 如何讲解一个C语言程序,解读第一个C++