詳細!Mybatis-plus常用API全套教程,我就不信你看完還不懂!
前言
官網:Mybatis-plus官方文件 簡化 MyBatis !
建立資料庫
資料庫名為mybatis_plus
建立表
建立user表
DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年齡', email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱', PRIMARY KEY (id) ); INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, '[email protected]'), (2, 'Jack', 20, '[email protected]'), (3, 'Tom', 28, '[email protected]'), (4, 'Sandy', 21, '[email protected]'), (5, 'Billie', 24, '[email protected]');
注意:-- 真實開發中往往都會有這四個欄位,version(樂觀鎖)、deleted(邏輯刪除)、gmt_create(建立時間)、gmt_modified(修改時間)
初始化專案
使用SpringBoot器 初始化!
匯入依賴
<!-- 資料庫驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- mybatis-plus --> <!-- mybatis-plus 是自己開發,並非官方的! --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency>
注意:儘量不要同時匯入 mybatis 和 mybatis-plus!避免版本的差異造成無法預知的問題。
連線資料庫
建立application.yml
spring: profiles: active: dev datasource: # 驅動不同 mysql 5 com.mysql.jdbc.Driver # mysql 8 com.mysql.cj.jdbc.Driver、需要增加時區的配置serverTimezone=GMT%2B8 url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root
業務程式碼
實體類
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper介面
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kuang.pojo.User;
import org.springframework.stereotype.Repository;
// 在對應的Mapper上面繼承基本的類 BaseMapper
@Repository // 代表持久層
public interface UserMapper extends BaseMapper<User> {
// 所有的CRUD操作都已經編寫完成了
}
注意點,我們需要在主啟動類上去掃描我們的mapper包下的所有介面
@MapperScan(“com.kwhua.mapper”)
測試
@SpringBootTest
class MybatisPlusApplicationTests {
// 繼承了BaseMapper,所有的方法都來自己父類
// 我們也可以編寫自己的擴充套件方法!
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
// 引數是一個 Wrapper ,條件構造器,這裡我們先設定條件為空,查詢所有。
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
所有資料輸出
配置日誌
我們所有的sql現在是不可見的,我們希望知道它是怎麼執行的,所有我們要配置日誌的輸出
application.yml檔案新增日誌配置
#配置日誌
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
檢視執行sql的日誌資訊
三.Mybatis-plus的CRUD
1.插入操作
// 測試插入
@Test
public void testInsert(){
User user = new User();
user.setName("kwhua_mybatis-plus_insertTest");
user.setAge(15);
user.setEmail("[email protected]");
int result = userMapper.insert(user); // 幫我們自動生成id
System.out.println(result); // 受影響的行數
System.out.println(user); // 看到id會自動填充。 }
看到id會自動填充。資料庫插入的id的預設值為:全域性的唯一id
主鍵生成策略
1)主鍵自增
1、實體類欄位上 @TableId(type = IdType.AUTO)
2、資料庫id欄位設定為自增!
3、再次測試(可以看到id值比上次插入的大1)
id的生成策略原始碼解釋
public enum IdType {
AUTO(0), // 資料庫id自增
NONE(1), // 未設定主鍵
INPUT(2), // 手動輸入
ID_WORKER(3), // 預設的方式,全域性唯一id
UUID(4), // 全域性唯一id uuid
ID_WORKER_STR(5); //ID_WORKER 字串表示法
}
以上不再逐一測試。
更新操作
@Test
public void testUpdate(){
User user = new User();
// 通過條件自動拼接動態sql
user.setId(1302223874217295874L);
user.setName("kwhua_mybatis-plus_updateTest");
user.setAge(20);
// 注意:updateById 但是引數是一個物件!
int i = userMapper.updateById(user);
System.out.println(i);
}
自動填充
建立時間、修改時間!這兩個欄位操作都是自動化完成的,我們不希望手動更新!
阿里巴巴開發手冊:所有的資料庫表都要配置上gmt_create、gmt_modified!而且需要自動化!
方式一:資料庫級別(工作中一般不用)
1、在表中新增欄位 gmt_create, gmt_modified
2、把實體類同步
private Date gmtCreate;
private Date gmtModified;
3、再次檢視
方式二:程式碼級別
1、刪除資料庫的預設值、更新操作!
2、實體類欄位屬性上需要增加註解
// 欄位新增填充內容
@TableField(fill = FieldFill.INSERT)
private Date gmt_create;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmt_modified;
3、編寫處理器來處理這個註解即可!
@Slf4j
@Component // 一定不要忘記把處理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入時的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
// setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
this.setFieldValByName("gmt_create",new Date(),metaObject);
this.setFieldValByName("gmt_modified",new Date(),metaObject);
}
// 更新時的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("gmt_modified",new Date(),metaObject);
}
}
4、測試插入和更新,檢查時間變化。
樂觀鎖
樂觀鎖 : 故名思意,十分樂觀,它總是認為不會出現問題,無論幹什麼不去上鎖!如果出現了問題,
再次更新值測試
悲觀鎖:故名思意,十分悲觀,它總是認為總是出現問題,無論幹什麼都會上鎖!再去操作!
樂觀鎖實現方式:
取出記錄時,獲取當前version
更新時,帶上這個version
執行更新時, set version = newVersion where version = oldVersion
如果version不對,就更新失敗
樂觀鎖:1、先查詢,獲得版本號 version = 1
-- A
update user set name = "kwhua", version = version + 1
where id = 2 and version = 1
-- B 執行緒搶先完成,這個時候 version = 2,會導致 A 修改失敗!
update user set name = "kwhua", version = version + 1
where id = 2 and version = 1
樂觀鎖測試
1、給資料庫中增加version欄位!
2、實體類加對應的欄位
@Version //樂觀鎖Version註解
private Integer version;
3、註冊元件
// 掃描我們的 mapper 資料夾
@MapperScan("com.kwhua.mapper")
@EnableTransactionManagement
@Configuration // 配置類
public class MyBatisPlusConfig {
// 註冊樂觀鎖外掛
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4、測試
// 測試樂觀鎖成功!
@Test
public void testOptimisticLocker(){
// 1、查詢使用者資訊
User user = userMapper.selectById(1L);
// 2、修改使用者資訊
user.setName("kwhua");
user.setEmail("[email protected]");
// 3、執行更新操作
userMapper.updateById(user);
}
version欄位已經由1變成了2
// 測試樂觀鎖失敗!多執行緒下
@Test
public void testOptimisticLocker2(){
// 執行緒 1
User user = userMapper.selectById(1L);
user.setName("kwhua111");
user.setEmail("[email protected]");
// 模擬另外一個執行緒執行了插隊操作
User user2 = userMapper.selectById(1L);
user2.setName("kwhua222");
user2.setEmail("[email protected]");
userMapper.updateById(user2);
// 自旋鎖來多次嘗試提交!
userMapper.updateById(user); // 如果沒有樂觀鎖就會覆蓋插隊執行緒的值!
}
可以看到執行緒1執行更新失敗
查詢操作
// 測試查詢
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}
// 測試批量查詢!
@Test
public void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
// 按條件查詢之一使用map操作
@Test
public void testSelectByBatchIds(){
HashMap<String, Object> map = new HashMap<>();
// 自定義要查詢
map.put("name","kwhua");
map.put("age",15);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
6.1分頁查詢
1、配置攔截器元件
// 分頁外掛
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2、直接使用Page物件即可!
// 測試分頁查詢
@Test
public void testPage(){
// 引數一:當前頁
// 引數二:頁面大小
Page<User> page = new Page<>(2,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
物理刪除
// 測試刪除
@Test
public void testDeleteById(){
userMapper.deleteById(1L);
}
// 通過id批量刪除
@Test
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(2L,3L));
}
// 通過map刪除
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","kwhua");
userMapper.deleteByMap(map);
}
邏輯刪除
物理刪除 :從資料庫中直接移除
邏輯刪除 :在資料庫中沒有被移除,而是通過一個變數來讓他失效! deleted = 0 => deleted = 1
管理員可以檢視被刪除的記錄!防止資料的丟失,類似於回收站!
1、在資料表中增加一個 deleted 欄位
2、實體類中增加屬性
@TableLogic //邏輯刪除
private Integer deleted;
3、配置
// 邏輯刪除元件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
配置檔案配置
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
4、測試
測試刪除
欄位值也從0修改成了1
測試查詢
效能分析外掛
作用:效能分析攔截器,用於輸出每條 SQL 語句及其執行時間
MP也提供效能分析外掛,如果超過這個時間就停止執行!
1、匯入外掛
/**
* SQL執行效率外掛
*/
@Bean
@Profile({"dev","test"})// 設定 dev test 環境開啟,保證我們的效率
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100); //ms 設定sql執行的最大時間,如果超過了則不執行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
條件構造器(Wrapper)
.isNotNull .gt
@Test
void contextLoads() {
// 查詢name不為空的使用者,並且郵箱不為空的使用者,年齡大於等於12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name") //不為空
.isNotNull("email")
.ge("age",18);
userMapper.selectList(wrapper).forEach(System.out::println); // 和我們剛才學習的map對比一下
}
.eq
@Test
void test2(){
// 查詢名字kwhua
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","kwhua");
User user = userMapper.selectOne(wrapper); // 查詢一個數據用selectOne,查詢多個結果使用List 或者 Map
System.out.println(user);
}
.between
@Test
void test3(){
// 查詢年齡在 20 ~ 30 歲之間的使用者
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,30); // 區間
Integer count = userMapper.selectCount(wrapper);// 查詢結果數
System.out.println(count);
}
.like
// 模糊查詢
@Test
void test4(){
// 查詢名字中不帶e且 郵箱以t開頭的資料
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 左 likelift %t ,右 likeRight t%
wrapper
.notLike("name","e")
.likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
.insql
// 模糊查詢
@Test
void test5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// id 在子查詢中查出來
wrapper.inSql("id","select id from user where id<3");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
.orderByAsc
//測試六
@Test
void test6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 通過id進行排序
wrapper.orderByAsc("id");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
程式碼自動生成器
可以在test資料夾在建立一個java類
// 程式碼自動生成器
public class generateCode {
public static void main(String[] args) {
// 需要構建一個 程式碼自動生成器 物件
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全域性配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("kwhua");//作者名稱
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆蓋
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);//實體屬性 Swagger2 註解
// 自定義檔案命名,注意 %s 會自動填充表實體屬性!
gc.setServiceName("%sService");
gc.setControllerName("%sController");
gc.setServiceName("%sService");
gc.setServiceImplName("%sServiceImpl");
gc.setMapperName("%sMapper");
gc.setXmlName("%sMapper");
mpg.setGlobalConfig(gc);
//2、設定資料來源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/kwhua_test?
useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// dsc.setDriverName("com.mysql.jdbc.Driver"); //mysql5.6以下的驅動
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.kwhua"); //包名
pc.setModuleName("model"); //模組名
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user","course"); // 設定要對映的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自動lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自動填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 樂觀鎖
strategy.setVersionFieldName("version");
//根據你的表名來建對應的類名,如果你的表名沒有下劃線,比如test,那麼你就可以取消這一步
strategy.setTablePrefix("t_");
strategy.setRestControllerStyle(true); //rest請求
//自動轉下劃線,比如localhost:8080/hello_id_2
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute(); //執行
}
}
執行主方法即可生成對應程式碼
最後
感謝你看到這裡,文章有什麼不足還請指正,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!