文章目錄
一、MyBatis VS JPA
JPA:
java持久層API,可以理解爲一種規範,Hibernate就是其具體一個實現。(目前比較常用的是SpringDataJpa,它是Spring提供的一套簡化開發的框架,按照約定好的方法命名規則,編寫dao層接口,就可以在不編寫實現情況下執行數據庫操作,還提供了除CRUD以外的功能,例如分頁、排序、複雜查詢等等,SpringDataJpa可以理解爲對JPA的再次封裝,底層仍舊是Hibernate)
Mybatis優勢:
1、SQL語句可以自由控制,更靈活、性能較高。
2、SQL與代碼分離,易於閱讀和維護。
3、提供XML標籤,支持編寫動態SQL語句。
JPA優勢:
JPA移植性比較好(Hibernate方言)
提供了很多CRUD方法、開發效率高(不用編寫sql語句)
對象化程度更高(面向對象開發思想)
Mybatis劣勢:
簡單CRUD操作需要編寫SQL語句(單表仍需要編寫Mapper接口方法和xml的sql)
XML中有大量sql需維護
mybatis自身功能有限
二、MyBatis-Plus簡介
Mybatis-plus簡介:Mybatis增強工具,只做增強,不作改變,簡化開發,提高效率。
MP在mybatis啓動的時候,它在mybatis的xml和註解注入之後,緊接着反射分析實體,然後注入到底層容器中。就是注入crud之類的。注入之前MP會進行判斷,是否已經注入同樣的方法,如果已經注入,就不在注入。它的注入時機在容器啓動時,所以MP使用crud、本身是無性能損耗的。
1、Crab:Mybatisplus3.0教學版。(MP核心程序員作品)
2、Crab:WEB極速開發框架。(MP項目負責人作品)
github項目地址:https://github.com/baomidou/mybatis-plus
碼雲項目地址:https://gitee.com/baomidou/mybatis-plus
Mybatis-plus特點:
1、無侵入:Mybatis-Plus 在 Mybatis 的基礎上進行擴展,只做增強不做改變,引入 Mybatis-Plus 不會對您現有的 Mybatis 構架產生任何影響,而且 MP 支持所有 Mybatis 原生的特性
2、依賴少:僅僅依賴 Mybatis 以及 Mybatis-Spring
3、損耗小:啓動即會自動注入基本CRUD,性能基本無損耗,直接面向對象操作
4、通用CRUD操作:內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求
5、多種主鍵策略:支持多達4種主鍵策略(內含分佈式唯一ID生成器),可自由配置,完美解決主鍵問題
6、支持ActiveRecord:支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可實現基本 CRUD 操作
7、支持代碼生成:採用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用(P.S. 比 Mybatis 官方的 Generator 更加強大!)
支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
8、內置分頁插件:基於Mybatis物理分頁,開發者無需關心具體操作,配置好插件之後,寫分頁等同於寫基本List查詢
9、內置性能分析插件:可輸出Sql語句以及其執行時間,建議開發測試時啓用該功能,能有效解決慢查詢
10、內置全局攔截插件:提供全表 delete 、 update 操作智能分析阻斷,預防誤操作
三、MyBatis-Plus快速入門
1、lombok簡介及安裝
lombok作用:提高開發效率,通過註解形式使javabean生成get、set、有參數、無參數、toString等方法,無需手動實現。
倘若不使用lombok可以使用的註解有:
註解介紹:
下面只是介紹了幾個常用的註解,更多的請參見: https://projectlombok.org/features/index.html
@Getter / @Setter
可以作用在類上和屬性上,放在類上,會對所有的非靜態(non-static)屬性生成Getter/Setter方法,放在屬性上,會對該屬性生成Getter/Setter方法。並可以指定Getter/Setter方法的訪問級別。
@EqualsAndHashCode
默認情況下,會使用所有非瞬態(non-transient)和非靜態(non-static)字段來生成equals和hascode方法,也可以指定具體使用哪些屬性。
@ToString
生成toString方法,默認情況下,會輸出類名、所有屬性,屬性會按照順序輸出,以逗號分割。
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
無參構造器、部分參數構造器、全參構造器,當我們需要重載多個構造器的時候,Lombok就無能爲力了。
@Data
@ToString, @EqualsAndHashCode, 所有屬性的@Getter, 所有non-final屬性的@Setter和@RequiredArgsConstructor的組合,通常情況下,我們使用這個註解就足夠了。
IDEA安裝lombok插件:
然後在maven的pom.xml引入依賴:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
2、入門小案例
步驟:
建庫建表===>引入依賴===>配置===>編碼===>測試
建一個mp名的數據庫,在建一個user表:
#創建數據庫
#使用查看全文
create table user ( id BIGINT(20) PRIMARY key not null comment '主鍵',
name varchar(30) default null comment '姓名',
age int(11) default null comment '年齡',
email varchar(50) default null comment '郵箱',
manager_id BIGINT(20) default null comment '直屬上級id',
create_time DATETIME default null comment '創建時間',
CONSTRAINT manager_fk foreign key (manager_id)
REFERENCES user (id)) ENGINE=INNODB CHARSET=UTF8;
#數據初始化
INSERT INTO user (id,name,age,email,manager_id,create_time)
VALUES (1087982257332887553, '豬頭', 20, '[email protected]', NULL,
'2019-01-11 14:20:20'),
(1088248166370832385,'小懶豬',20,'[email protected]', 1087982257332887553,
'2019-02-05 11:12:22'),
(1088250446457389058,'小白',18,'[email protected]', 1088248166370832385,
'2019-02-14 08:31:16'),
(1094590409767661570,'小黑',21,'[email protected]', 1088248166370832385,
'2019-01-14 09:15:15'),
(1094592041087729666,'小可耐',22,'[email protected]', 1088248166370832385,
'2019-01-14 09:48:16');
然後建一個Spring Initializr工程:
pom.xml依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Mybatis-Plus啓動器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
創一個application.yaml,進行配置:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=GMT%2B8
username: root
password: 1214
編寫實體類:
entity/User.java:
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("user")
public class User {
/**
* 主鍵
*/
private Long id;
/**
* 姓名
*/
@TableField(value = "name", condition = SqlCondition.LIKE)
private String name;
/**
* 年齡
*/
@TableField(condition = "%s<#{%s}")
private Integer age;
/**
* 郵箱
*/
private String email;
/**
* 直屬上級id
*/
private Long managerId;
/**
* 創建時間
*/
private Date createTime;
/*
* 備註(不與數據庫字段對應) # transient 不參與序列化
*/
@TableField(exist = false)
private String remark;
}
編寫dao接口:
UserMapper.java:
public interface UserMapper extends BaseMapper<User> {
}
在啓動類中添加註解:@MapperScan(“com.mp.first_mp.dao”),進行掃描
最後就是編寫測試類:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SimpleTest {
@Autowired
private UserMapper userMapper;
@Test
public void select() {
List<User> list = userMapper.selectList(null);
Assert.assertEquals(5, list.size());
list.forEach(System.out::println);
}
}
查看效果:
運行是成功的,我們可以發現相對於使用MyBatis來說,MyBatis-plus不用編寫xml文件編寫那些繁瑣的SQL語句,簡單快速的MyBatis-plus的就到這裏,若還有興趣就繼續看下去吧ヾ(◍°∇°◍)ノ゙
四、基本使用
1、通用傳統模式簡介及通用mapper新增方法
相信對SSM比較熟系的小夥伴應該對SSM傳統編程模式都比較熟系:
接口中寫抽象方法===>XML或註解寫SQL===>Service中調用接口===>Controller中調用
爲了方便大家觀察,在application.yaml多增加應該日誌的輸出:
logging:
level:
root: warn
com.mp.first_mp.dao: trace
pattern:
console: '%p%m%n'
進行測試:
@Test
public void insertTest() {
User user = new User();
user.setName("小灰");
user.setAge(20);
user.setEmail("[email protected]");
user.setManagerId(1088248166370832385L);
user.setCreateTime(new Date());
int rows = userMapper.insert(user);
System.out.println("影響記錄數:" + rows);
}
運行結果:
倘若大家觀察得仔細可以發現主鍵id並沒有設定自增,那爲什麼沒有出現報錯呢???
原來MP的默認主鍵策略是基於雪花算法的自增主鍵,在MP的源碼中有雪花算法的實現代碼。
額~~~可能有小夥伴不知道什麼是雪花算法,大家可以看看這位博主寫的文章:雪花算法的原理和實現Java
2、常用註解
mybatis-plus:
主鍵採用雪花算法生成值的前提是實體類的主鍵屬性名稱必須爲id。
mybatis-plus:
數據表字段帶有_的可以自動映射到駝峯式命名的屬性上(t_user——》tUser)。
註解:
1.數據庫名不同,在類上增加@TableName(“mp_user”)
2.主鍵ID的駝峯一般無法識別,在主鍵屬性上增加@TableId
3.屬性與字段名不相同,在屬性上增加@TableField(“name”)
@TableName(“數據庫表名”):
使用場景實體類名稱和數據表名不一致時,通過它指定表名,此時就可以使用mp的單表操作。
@TableId(“主鍵名”):
使用場景實體類屬性名稱和數據表主鍵不是id時,通過它聲明該屬性爲主鍵,就可以採用雪花算法生成主鍵值操作。
@TableField(“字段名”):
使用場景實體類屬性名稱和數據表字段名不一致時,通過它指定數據表字段名稱,就可以和實體類屬性對應。
3、排除非表字段的三種方式
使用場景: 實體類中的某個屬性不對應表中的任何字段,只是用於保存臨時數據,或者臨時組裝的數據。
使用方式
1、 transient修飾實體類屬性(修飾的屬性不會被序列化)。
缺陷:有些需求需要序列化該字段。
2、 static修飾屬性(前提手動實現get、set方法,Lombok對靜態屬性不會提供get、set方法)。
缺陷:每個對象的屬性值一致。
3、 @TableField(exist=false),這個註解用來表示數據表中不存在該字段,默認是true。
五、MyBatis-Plus查詢方法
1、普通查詢
普通查詢:使用方式爲實現BaseMapper接口對象調用該方法。
1、T selectById(Serializable id):使用場景爲通過主鍵查詢,只要該主鍵類型實現了Serialzable接口即可。
@Test
public void selectById() {
User user = userMapper.selectById(6);
System.out.println(user);
}
2、List selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList):使用場景爲通過主鍵的集合去批量查詢,前提主鍵的類型實現了Serializable接口。
@Test
public void selectBatchById() {
List<Long> userListId = Arrays.asList(1L, 2L, 3L);
List<User> userList = userMapper.selectBatchIds(userListId);
userList.forEach(System.out::println);
}
3、List selectByMap(@Param(Constants.COLUMN_MAP) Map<String,Object> columnMap):使用場景爲傳入一個Map集合,key爲表字段,value爲表字段值。
注意:Map的key爲數據表的字段名,不是實體類屬性名。
@Test
public void selectByMap() {
Map<String, Object> userMap = new HashMap<>();
userMap.put("age", 20);
List<User> userList = userMapper.selectByMap(userMap);
userList.forEach(System.out::println);
}
2、條件構造器查詢
BaseMapper以條件構造器(Wrapper)爲參數的查詢方法
AbstractWrapper抽象類:提供了很多條件構造器。
List selectList(@Param(Constans.WRAPPER) Wrapper queryWrapper):
使用場景:對於一些有特殊條件的查詢,比如模糊查詢、條件查詢等。
使用方法:QueryWrapper爲查詢條件構造器,它是AbstractWrapper的一個子類。
生成條件構造器
方式一:QueryWrapper queryWrapper=new QueryWrapper();
方式二:QueryWrapper query=Wrappers.query();
注意: 條件構造器AbstractWrapper的條件構造器方法key都爲數據表字段,value爲實際值。例如:like(Column,value)、gt(Column,value)等。
模糊條件構造器:like,小於條件構造器:lt。
範圍條件構造器:between,非空條件構造器:isNotNull。
模糊右通配符條件構造器:likeRight,或條件構造器:or。
大於等於條件構造器:ge,升序條件構造器:orderAsc。
降序條件構造器:orderDesc。
Mysql函數
date_format(日期,‘格式’):將日期按照格式進行插入或者返回。
例如: date_format(now(),’%Y-%m-%d’)。
動態條件構造器:apply,範圍條件構造器:insql。
注意: 如果{0}替換爲實際值,可能會造成sql注入。
and括號條件構造器:and()
注意: 怕有些小夥伴不瞭解這個是什麼:wq -> wq.xxx這種類型的表達式,這個是java8引入的lambda表達式的語法,箭頭左邊是變量名,箭頭右邊是自己編寫的代碼邏輯,如果感興趣你可以瞭解一下java的lambda表達式,當然打印方式也是lambda表達式
or括號條件構造器:or()
非and開頭的條件構造器:nested()
In條件構造器:In(column,Collection)
last條件構造器:last(sql)。注意:有sql注入風險。確保參數沒有風險再使用。
3、select不列出全部字段
select不列出全部字段
select(String …columns)
如果返回的字段數量很多,此時採用如下的select,也可以放置在後面
select(Class entityClass,Predicate predicate)
第一個參數爲實體類對象;
第二個參數相當於排除返回的字段.
4、condition作用
如果使用的是IDEA需要添加依賴pom.xml:
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
條件構造器(abstractWrapper)中 condition(構造的方法的boolean類型參數) 作用。
如下:like方法調用重載的方法,重載方法中第一個參數。
作用:該條件是否加入最後生成的sql中。
使用方法:如果爲true就加入,如果false就不加入。
使用場景:類似於動態的sql拼接。
傳統使用:
mp方式:
5、實體作爲條件構造器構造方法的參數
創建條件構造器時傳入實體對象
private SharedString sqlSelect = new SharedString();
public QueryWrapper() {
this(null);
}
public QueryWrapper(T entity) {
super.setEntity(entity);
super.initNeed();
}
QueryWrapper一個參數的構造方法,如果傳入一個部不爲null的對象,默認會進行進行等值比較,也就是where後拼接條件。
注意:通過entity參數生成的等值和QueryWrapper的條件構造方法生成的沒有任何關係。
舉例驗證:
注意:使用時要慎重,因爲他們都會在sql中進行拼接。
使用場景:如果允許使用實體類去接受參數,那麼就可以不用調用條件構造器,而是直接使用構造方法傳入參數即可。
特殊操作:可以通過在實體類上添加註解,指定該屬性使用那種操作,默認使用等值。
SqlCondition類:定義了一些常量,包括等值、不等於、like、左邊like、右邊like。
如果提供的常量無法滿足需求,就可以自己在註解中編寫常量表達式,例如小於。
6、AllEq用法
Alleq(Map<R,V> params)
使用方法:傳入一個map集合對象,就會按照等值進行操作。key爲字段名稱,value爲字段值。如果字段的值爲null,那麼sql就會拼接爲is null這種形式。
如果傳入的null,想要忽略掉,也就是不進行拼接,那麼就傳入第二個參數爲false。
allEq的第二種方法,參數1爲過濾函數,它是一個函數式接口。
上圖就是判斷name是不等於name,如果不等於就返回true,就會過濾掉,所以沒有拼接name。也可以判斷值。注意需要考慮類型的問題
7、其他使用條件構造器的方法
其他以條件構造器的方法
1、selectMap:List集合的泛型不再是實體,而是map集合。其中key表示字段名,value表示字段值。
使用場景1:當實體類屬性非常多時,不易查看。如果返回的是一個實體類,那麼即使我們設定了返回字段,那麼它的值爲null,但是屬性仍然存在。如果返回的是Map類型,當指定了返回字段時,那麼沒返回的就不會存在。
使用場景2:當返回的不是一條一條記錄時,也就是返回的字段不在實體類屬性中,比如一些統計,像平均值,最大值,最小值這樣的。
2、selectObject:List集合的泛型不再是實體,而是Object,只返回第一個字段的值。其他的會被捨棄。
使用場景:只返回一列時可以使用它。
3、selectCount:查詢符合條件的總記錄數的。
注意:使用它時,就不能指定返回的列了,因爲它會在後面拼接COUNT(1)。
4、selectOne:查詢符合條件的數據,只會返回一條數據。
注意: 查詢的結果必須是一條或者查不到(多於1條就會報錯)。
8、lambda條件構造器
lambda條件構造器(類似mp條件構造器,防誤寫)
lambda條件構造器使用場景:
不需要我們手動在構造條件時去書寫字段名稱。
lambda條件構造器使用方法:
lambda條件構造器的創建有3種方式
1、通過查詢構造器QueryWrapper創建
2、通過new直接創建lambda條件構造器
3、通過構造器工具類Wrappers創建(此時需要泛型)
4、3.0.7新增的創建lambda條件構造器,通過LambdaQueryChainWrapper,並且需要一個Mapper接口作爲參數(通過源碼可以,它是對普通查詢構造器的再次封裝,源碼中仍然是通過Mapper接口去調用)。
六、自定義SQL及分頁查詢
1、使用條件構造器的自定義sql
使用場景:當使用條件構造器去構造sql的方法不能滿足需求時(前提:mybatisplus版本大於3.0.7)。
使用方法:
注意:${ew.customSqlsegment}可以使條件構造器構造的sql被執行。
mybatis-plus配置xml文件路徑(springboot項目):
不過由於IDEA系列編輯器,XML文件是不能放在 java 文件夾中的,IDEA默認不會編譯源碼文件夾中的 XML文件,所以可以通過在pom.xml中加入:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
即可在xml中進行編寫SQL語句。
2、分頁查詢
分頁查詢
1、mybatis分頁查詢(mybatis的rowBounds實現的分頁不是物理分頁,可以理解爲邏輯或者內存分頁)
拓展:內存分頁弊端,數據量大時佔用過多內存,第一次查詢速度慢。
2、mybatis-plus插件實現物理分頁
a、配置mybatis-plus插件
BaseMapper提供了兩個分頁方法:
這兩個方法主要區別如下圖,返回的數據是實體類型,還是map類型。
IPage.java:
b、分頁使用
分頁map形式
使用分頁時,不查詢總記錄數:第三個參數爲true表示查詢總記錄數,否則就不查詢。
Page.class:
當分頁查詢查詢的是多表時使用分頁:
倘若需要多表聯查,可以在xml文件裏編寫多表聯查的SQL,一樣可以實現其功能ヾ(◍°∇°◍)ノ゙
如:
在xml裏編寫需要的多表查詢語句即可。
七、更新與刪除
1、mybatis-plus更新
1、根據id更新
使用場景:根據實體類主鍵屬性進行更新,其他屬性有值就更新。
使用方法:如下
2、以條件構造器作爲參數進行更新
使用場景:更新條件爲其他時。
使用方法:如下
條件構造器傳入實體時的使用(和QueryWrapper類似),它會將實體屬性作爲更新的條件。
3、條件構造器中set方法使用
如果更新少量字段可使用如下方式:
lambda方式更新:
通過構造器鏈進行直接更新:
2、mybatis-plus刪除方法
1、根據id刪除方法——deleteById(前提:實體類主鍵屬性上有@TableId註解)
2、普通刪除方法
3、以條件構造器爲參數刪除方法
八、AR模式、主鍵策略和基本配置
1、ActiveRecord模式
簡介:活動記錄,領域模型模式,直接通過實體操作數據庫(java的一個實體類對應數據庫的一張表,而一個實例對應表中一行記錄)
MP中AR模式的實現(兩個前提:實體類需要繼承Model;mapper接口實現BaseMapper)
直接用實體即可操作數據庫:
insertOrUpdate():
如果實體的主鍵不是null,那麼就會先查詢,如果有記錄就更新,沒有就插入。是null直接進行插入。
注意:如下圖方法刪除不存在的也返回true.
至於其他方法的使用介紹,可以查看Model.java源碼٩(๑❛ᴗ❛๑)۶
2、主鍵策略
mp的主鍵策略定義在了IdTyoe的枚舉類中:(下面是源碼)
局部策略:
在主鍵字段配置@TableId(type=IdType.AUTO)
全局策略:
在application.yaml配置中添加:
注意: 局部策略優於全局策略
3、基本配置
可在查看官網地址:https://mybatis.plus/
九、通用的Service
詳情可查看IService.java的源碼。
下面是部分方法的使用:
1、基本方法
因爲數據數大於1,所以默認返回第一條
2、批量操作操作
不指定
指定
3、鏈式調用方法
查詢:
更新:
刪除:
關於MyBatis-Plus的詳細快速入門的學習就到這裏,Thanks♪(・ω・)ノ