【Java开发】 Mybatis-Plus 02:Mapper-CRUD+自动填充+乐观锁
今天正好學習了Mybatis-Plus Mapper的Insert、Update 及自動填充功能的使用,特來和大家分享一下,需要注意的是我用的Mybatis-Plus版本是3.5.2,基礎配置可見01。
目錄
1?Insert
1.1 測試插入
1.2?主鍵生成策略
1.2.1?主鍵自增:
1.2.2?手動輸入:
2?Update
3?自動填充
3.1 方式一:數據庫級別
①數據表增加字段:create_time,update_time
②實體類中同步!
③查看結果
3.2 方式二:通過代碼
①取消數據庫的默認值,更新操作!
②實體類字段屬性上需要增加注解
③編寫處理器來處理注解!
④測試插入/更新,觀察時間:
⑤輸出結果
4?樂觀鎖
4.1?數據庫中增加version字段
4.2?實體類加對應的字段
4.3?注冊組件
4.4?測試
① 測試樂觀鎖成功
② 測試樂觀鎖失敗
5 Select
5.1 普通查詢
① 通過id查詢單個用戶
② 通過id查詢多個用戶
③?條件查詢 通過map封裝
5.2 分頁查詢
① 配置攔截器組件
②?直接使用page對象
③ 查看結果
6 Delete
6.1 普通刪除
6.2?邏輯刪除
① 數據表增加deleted字段
② 實體類中添加對應屬性
③?配置!
④?測試邏輯刪除
源碼地址:尹煜 / mybatis_plus_study · GitCode
1?Insert
1.1 測試插入
路徑:src/test/java/com/yinyu/MybatisPlusApplicationTests.java
//測試插入 @Test public void testInsert(){User user = new User();user.setName("尹煜");user.setAge(3);user.setEmail("yinyu@163.com");int result = userMapper.insert(user);//幫助用戶自動生成idSystem.out.println(result);//受影響的行數System.out.println(user);//通過日志發現id會自動回填 }輸出結果:
需要注意的是,數據庫插入的id的默認值為全局的唯—id,而且是自動生成的。
1.2?主鍵生成策略
分布式系統唯一Id生成方案鏈接:分布式系統唯一ID生成方案匯總
源碼解釋:
public enum IdType {AUTO, //數據庫id自增NONE;//未設置主鍵INPUT, //手動輸入ID_WORKER, //默認的全局唯一idUUID, //全局唯一id uuidID_WORKER_STR, //字符串表示法** } Mybatis-Plus用的是Twitter的snowflake算法:snowflake是Twitter開源的分布式ID生成算法,結果是一個long型的ID。其核心思想是:使用41bit作為毫秒數,10bit作為機器的ID(5個bit是數據中心(北京、香港···),5個bit的機器ID),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 ID),最后還有一個符號位,永遠是0。
1.2.1?主鍵自增:
AUTO 我們需要配置主鍵自增
①在實體類字段上配置@TableId(type = IdType.AUTO)
②數據庫字段設置自增
我用的是DBeaver可視化軟件
?③執行testInsert,輸出結果:
1.2.2?手動輸入:
INPUT 就需要自己寫id ①在實體類字段上配置@TableId(type = IdType.INPUT)?②執行testInsert(id:null)
?可以看到插入成功,但是id為null,不過mysql會匹配成自增輸入id形式,所以也沒有報錯。
③執行testInsert(id:6)
?
2?Update
路徑:src/test/java/com/yinyu/MybatisPlusApplicationTests.java
//測試更新 public void testUpdate(){User user = new User();user.setId(6L);user.setName("無關風月");//updateById,但是參數是個user!!int result = userMapper.updateById(user);System.out.println(result);System.out.println(user); }輸出結果:
3?自動填充
創建時間、更改時間! 這些操作一般都是自動化完成,我們不希望手動更新
阿里巴巴開發手冊︰幾乎所有的表都要配置 gmt_create、gmt_modified !而且需要自動化
3.1 方式一:數據庫級別
注意:工作中不允許修改數據庫級別,不推薦此種方式①數據表增加字段:create_time,update_time
?②實體類中同步!
路徑:src/main/java/com/yinyu/pojo/User.java
private Date createTime;//駝峰命名 private Date updateTime;③查看結果
3.2 方式二:通過代碼
①取消數據庫的默認值,更新操作!
?注意不是刪掉字段,而是取消默認值等👇
?②實體類字段屬性上需要增加注解
路徑:src/main/java/com/yinyu/pojo/User.java
//字段 字段添加填充內容 @TableField(fill = FieldFill.INSERT)//value = ("create_time"), private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;③編寫處理器來處理注解!
自動填充功能官方文檔:自動填充功能 | MyBatis-Plus
官方已更新setFieldValByName方法為strictInsertFill或fillStrategy等,不過需要將mybatis-plus版本升級到3.3.0及以上,由于本文mybatis-plus版本在3.5.2,采用官網推薦的方法👇
路徑:src/main/java/com/yinyu/handler/MyMetaObjectHandler.java
@Slf4j//日志 @Component public class MyMetaObjectHandler implements MetaObjectHandler {@Override//插入時的填充策略public void insertFill(MetaObject metaObject) {log.info("==start insert ······==");//setFieldValByName(java.lang.String fieldName, java.lang.Object fieldVal, org.apache.ibatis.reflection.MetaObject metaObject)this.strictInsertFill(metaObject,"createTime",Date.class, new Date());this.strictInsertFill(metaObject,"updateTime",Date.class, new Date());}@Override//更新時的填充策略public void updateFill(MetaObject metaObject) {log.info("==start update ······==");this.strictUpdateFill(metaObject,"updateTime",Date.class, new Date());} }④測試插入/更新,觀察時間:
//測試插入@Testpublic void testInsert(){User user = new User();user.setName("testMetaObjectInsert");user.setAge(3);user.setEmail("yinyu@163.com");int result = userMapper.insert(user);//幫助用戶自動生成idSystem.out.println(result);//受影響的行數System.out.println(user);//通過日志發現id會自動回填}//測試更新@Testpublic void testUpdate(){User user = new User();user.setId(6L);user.setName("testMetaObjectUpdate");int result = userMapper.updateById(user);System.out.println(result);System.out.println(user);}⑤輸出結果
4?樂觀鎖
面試過程中經常被問到樂觀鎖/悲觀鎖👇樂觀鎖:顧名思義十分樂觀,他總是認為不會出現問題,無論干什么都不上鎖!如果出現了問題,再次更新值測試。
悲觀鎖:顧名思義十分悲觀,他總是認為出現問題,無論干什么都會上鎖!再去操作!
樂觀鎖實現方式:
-
取出記錄時,獲取當前version
-
更新時,帶上這個version
-
執行更新時,set version = newVersion where version = oldVersion
-
如果version不對,就更新失敗
接下里實踐一下~
4.1?數據庫中增加version字段
4.2?實體類加對應的字段
路徑:src/main/java/com/yinyu/pojo/User.java
@Version//樂觀鎖version注解 private Integer version;說明:
- 支持的數據類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整數類型下?newVersion = oldVersion + 1
- newVersion?會回寫到?entity?中
- 僅支持?updateById(id)?與?update(entity, wrapper)?方法
- 在?update(entity, wrapper)?方法下,?wrapper?不能復用!!!
4.3?注冊組件
路徑:src/main/java/com/yinyu/config/MyBatisPlusConfig.java
@MapperScan("com.yinyu.mapper")//交給mybatis做的,可以讓這個配置類做掃描 @EnableTransactionManagement//自動管理事務 @Configuration//配置類 public class MyBatisPlusConfig {/*** 新版*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;} }4.4?測試
① 測試樂觀鎖成功
@Test//測試樂觀鎖成功 public void testOptimisticLocker1(){//1、查詢用戶信息User user = userMapper.selectById(1L);//2、修改用戶信息user.setAge(18);user.setEmail("yinyu@qq.com");//3、執行更新操作userMapper.updateById(user); } 首先執行查詢sql,然后進行修改,version加1② 測試樂觀鎖失敗
@Test//測試樂觀鎖失敗 多線程下 public void testOptimisticLocker2(){//線程1User user1 = userMapper.selectById(2L);user1.setAge(18);user1.setEmail("yinyu@qq.com");//線程2,模擬另外一個線程執行了插隊操作User user2 = userMapper.selectById(2L);user2.setAge(17);user2.setEmail("yinyu17@qq.com");userMapper.updateById(user2);//自旋鎖來多次嘗試提交!userMapper.updateById(user1);//如果沒有樂觀鎖就會覆蓋插隊線程的值 }?
由于自旋鎖多次提交,最后覆蓋的是線程1的數據,不過version依舊為2。5 Select
5.1 普通查詢
① 通過id查詢單個用戶
@Test//通過id查詢單個用戶 public void testSelectById(){User user = userMapper.selectById(1L);System.out.println(user); }② 通過id查詢多個用戶
@Test//通過id查詢多個用戶 public void testSelectBatchIds(){List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));users.forEach(System.out::println); }③?條件查詢 通過map封裝
關于復雜的查詢之后會用wrapper操作 @Test//通過條件查詢之一 map public void testMap(){HashMap<String, Object> map = new HashMap<>();//自定義要查詢的map.put("name","尹煜");map.put("age",3);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println); }5.2 分頁查詢
分頁在網站的使用非常之多!
1、原始的limit分頁
2、pageHelper第三方插件
3、MybatisPlus其實也內置了分頁插件!!!
① 配置攔截器組件
路徑:src/main/java/com/yinyu/config/MyBatisPlusConfig.java
//新的分頁插件,,一緩和二緩遵循mybatis的規則 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 將上述代碼插入下邊就行②?直接使用page對象
@Test//測試分頁查詢 public void testPage(){//參數一current:當前頁 參數二size:頁面大小//使用了分頁插件之后,所有的分頁操作都變得簡單了Page<User> page = new Page<>(2,3);userMapper.selectPage(page,null);page.getRecords().forEach(System.out::println);System.out.println("總頁數==>"+page.getPages()); }③ 查看結果
6 Delete
6.1 普通刪除
類似select~
@Test public void testDeleteById(){userMapper.deleteById(1L); } @Test public void testDeleteBatchIds(){userMapper.deleteBatchIds(Arrays.asList(2L,3L)); } @Test public void testD(){HashMap<String, Object> map = new HashMap<>();map.put("age","18");map.put("name","john");userMapper.deleteByMap(map); }6.2?邏輯刪除
物理刪除:從數據庫中直接刪除
邏輯刪除:在數據庫中沒有被刪除,而是通過一個變量來使他失效! deleted=0 ==> deleted=1
場景:管理員可以查看被刪除的記錄!防止數據的丟失,類似于回收站!
① 數據表增加deleted字段
② 實體類中添加對應屬性
路徑:src/main/java/com/yinyu/pojo/User.java @TableLogic//邏輯刪除注解 private Integer deleted;③?配置!
3.3版本后只需要在下邊或yaml中配置即可
路徑:src/main/resources/application.properties
#配置邏輯刪除 沒刪除的為0 刪除的為1 mybatis-plus.global-config.db-config.logic-delete-field: flag mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0④?測試邏輯刪除
@Test public void testDeleteById(){userMapper.deleteById(4L); } 發現: 記錄還在,deleted變為1再次測試查詢被刪除的用戶,發現查詢為空
@Test public void testselect(){User user = userMapper.selectById(4);System.out.println(user); }👇
說明邏輯刪除已成功
以上所有的CRUD及其擴展操作,我們都必須精通掌握!會大大提高工作寫項目的效率!
總結
大家如果有疑問都可以評論提出,有不足之處請大家批評指正,希望能多結識這方面的朋友,共同學習、共同進步。
總結
以上是生活随笔為你收集整理的【Java开发】 Mybatis-Plus 02:Mapper-CRUD+自动填充+乐观锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个-书,字 我惆怅
- 下一篇: 马士兵java框架_马士兵java架构师