MybatisPlus學習整理(二)

看這篇內容以前建議先看一下 MyBatisPlus學習整理(一)
很少bibi,直接建表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NULL DEFAULT NULL COMMENT '主鍵',
  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `age` int(11) NULL DEFAULT NULL COMMENT '年齡',
  `email` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '郵箱',
  `manager_id` bigint(20) NULL DEFAULT NULL COMMENT '直屬上級id',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '建立時間',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改時間',
  `version` int(11) NULL DEFAULT 1 COMMENT '版本',
  `deleted` int(1) NULL DEFAULT 0 COMMENT '邏輯刪除標識(0,未刪除;1,已刪除)'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES (1234, '大boss', 40, 'boss@163.com', NULL, '2019-10-02 10:08:02', '2019-10-02 10:08:05', 1, 0);
INSERT INTO `user` VALUES (2345, '王天風', 25, 'wtf@163.com', 1234, '2019-10-02 10:09:07', '2019-10-02 10:09:10', 1, 0);
INSERT INTO `user` VALUES (2346, '李藝偉', 28, 'lyw@163.com', 2345, '2019-10-02 10:10:09', '2019-10-02 10:10:12', 1, 0);
INSERT INTO `user` VALUES (3456, '張雨綺', 31, 'zyq@163.com', 2345, '2019-10-02 10:10:54', '2019-10-02 10:10:58', 1, 0);
INSERT INTO `user` VALUES (4566, '劉雨紅', 32, 'lyh@163.com', 2345, '2019-10-02 10:11:51', '2019-10-02 10:11:55', 1, 0);
SET FOREIGN_KEY_CHECKS = 1;

項目延用MyBatisPlus學習整理(一)https://github.com/xiao-ren-wu/notebook/tree/master/mybatis-plus-demohtml

邏輯刪除

  1. 設定邏輯刪除規則

在配置文件中配置邏輯刪除和邏輯未刪除的值mysql

mybatis-plus:
  global-config:
      logic-not-delete-value: 0
      logic-delete-value: 1
  1. 在pojo類中在邏輯刪除的字段加註解 @TableLogic
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
    @TableId(type = IdType.AUTO)
    private Long id;
    @TableField(condition = SqlCondition.LIKE)
    private String name;
    private Integer age;
    private String email;
    private Long managerId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Integer version;
    @TableLogic
    private Integer deleted;
}
  1. 經過id邏輯刪除
@Test
    public void deleteById(){
        userMapper.deleteById(4566L);
    }

  1. 查詢中排除刪除標識字段及注意事項

邏輯刪除字段只是爲了標識數據是否被邏輯刪除,在查詢的時候,並不想也將該字段查詢出來。
咱們只須要在delete字段上增長@TableField(select = false)mybatisplus在查詢的時候就會自動忽略該字段。git

@Test
    public void selectIgnoreDeleteTest(){
        userMapper.selectById(3456L);
    }


自定義sql,MybatisPlus不會忽略deleted屬性,須要咱們手動忽略github

自動填充

MybaitsPlus在咱們插入數據或者更新數據的時候,爲咱們提供了自動填充功能。相似MySQL提供的默認值同樣。
若是咱們須要使用自動填充功能,咱們須要在實體類的相應屬性上加@TableField註解,並指定何時進行自動填充。mybatisPlus爲咱們提供了三種填充時機,在FieldFill枚舉中spring

public enum FieldFill {
    /**
     * 默認不處理
     */
    DEFAULT,
    /**
     * 插入時填充字段
     */
    INSERT,
    /**
     * 更新時填充字段
     */
    UPDATE,
    /**
     * 插入和更新時填充字段
     */
    INSERT_UPDATE
}

設置好以後,咱們還須要編寫具體的填充規則,具體是編寫一個填充類並交給Spring管理,而後實現MetaObjectHandler接口中的insertFillupdateFill方法。
eg:sql

  1. 插入User對象的時候自動填充插入時間,更新User對象的時候自動填充更新時間。
  • 指定實體類中須要自動填充的字段,並設置填充時機
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
    ...
    @TableField(fill = INSERT)
    private LocalDateTime createTime;
    @TableField(fill = UPDATE)
    private LocalDateTime updateTime;
    ...
}
  • 編寫填充規則
@Component
public class MyMetaObjHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        if(metaObject.hasSetter("createTime")){
            setInsertFieldValByName("createTime", LocalDateTime.now(),metaObject);
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        if(metaObject.hasSetter("updateTime")){
            setUpdateFieldValByName("updateTime",LocalDateTime.now(),metaObject);
        }
    }
}
解釋一下爲何要用if判斷是否有對應的屬性
mybatisPlus在執行插入或者更新操做的時候,每次都會執行該方法,有些表中是沒有設置自動填充字段的,並且有些自動填充字段的值的獲取比較消耗系統性能,因此爲了避免必要的消耗,進行if判斷,決定是否須要填充。

有些時候咱們已經設置了屬性的值。不想讓mybatisPlus再自動填充,也就是說咱們沒有設置屬性的值,mybatisPlus進行填充,若是設置了那麼就用咱們設置的值。這種狀況咱們只須要在填充類中提早獲取默認值,而後使用該默認值就能夠了。數據庫

@Override
    public void updateFill(MetaObject metaObject) {
        if(metaObject.hasSetter("updateTime")){
            Object updateTime = getFieldValByName("updateTime", metaObject);
            if(Objects.nonNull(updateTime)){
                setUpdateFieldValByName("updateTime",updateTime,metaObject);
            }else{
                setUpdateFieldValByName("updateTime",LocalDateTime.now(),metaObject);
            }
        }
    }

樂觀鎖

樂觀鎖適用於讀多寫少的狀況,更新數據的時候不使用「鎖「而是使用版本號來判斷是否能夠更新數據。經過不加鎖來減少數據更新時間和系統的性能消耗,進而提升數據庫的吞吐量。CAS機制就是一種典型的樂觀鎖的形式。
樂觀鎖是邏輯存在的一種概念,咱們若是使用樂觀鎖須要手動在表的加上version字段。mybatis

  1. mysql使用樂觀鎖僞代碼示例:
update user 
set balabala....
where balabala... and version = xxx
樂觀鎖

1.配置類中注入樂觀鎖插件app

@Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
  1. 實體類中的版本字段增長@version註解
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
    ...
    @Version
    private Integer version;
    ...
}
  1. test

更新王天風的年齡ide

@Test
    public void testLock(){
        int version = 1;
        User user = new User();
        user.setEmail("wtf@163.com");
        user.setAge(34);
        user.setId(2345L);
        user.setManagerId(1234L);
        user.setVersion(1);
        userMapper.updateById(user);

    }

image.png
數據庫中的version已經變成2
image.png

注意事項:
  1. 支持的類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  2. 整數類型下newVerison = oldVersion+1
  3. newVersion會寫到entity中
  4. 僅支持updateById(id)與update(entity,wrapper)方法
  5. 在update(entiry,wrapper)方法下,wrapper不能複用

性能分析

  1. 配置類中注入性能分析插件
@Bean
   // @Profile({"dev,test"})
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        // 格式化sql輸出
        performanceInterceptor.setFormat(true);
        // 設置sql執行最大時間,單位(ms)
        performanceInterceptor.setMaxTime(5L);

        return performanceInterceptor;
    }

執行sql就能夠打印sql執行的信息了
image.png

依靠第三方插件美化sql輸出

https://mp.baomidou.com/guide/p6spy.html

  1. 第三方依賴
<dependency>
            <groupId>p6spy</groupId>
            <artifactId>p6spy</artifactId>
            <version>3.8.5</version>
        </dependency>
  1. 更改配置文件中的dirver和url
spring:
  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
#    url: jdbc:mysql://localhost:3306/test?serverTimezone=CTT&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://localhost:3306/test?serverTimezone=CTT&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
  1. 增長spy.properties配置文件
module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定義日誌打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日誌輸出到控制檯
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日誌系統記錄 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 設置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前綴
useprefix=true
# 配置記錄 Log 例外,可去掉的結果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,batch,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 實際驅動可多個
#driverlist=org.h2.Driver
# 是否開啓慢SQL記錄
outagedetection=true
# 慢SQL記錄標準 2 秒
outagedetectioninterval=2
  1. test

注意

開啓性能分析會消耗系統的性能,因此性能分析插件要配合@Profile註解執行使用的環境。

SQL注入器 ->_-> 封裝自定義通用SQL

實現步驟:

  1. 建立定義方法的類
  2. 建立注入器
  3. 在mapper中加入自定義方法

eg: 編寫一個刪除表全部數據的方法

  1. 建立定義方法的類
public class DeleteAllMethod extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        // 執行的sql
        String sql = "delete from " + tableInfo.getTableName();
        // mapper接口方法名
        String method = "deleteAll";
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, mapperClass);
        return addDeleteMappedStatement(mapperClass, method, sqlSource);
    }
}
  1. 建立注入器。添加本身的方法
@Component
public class MySqlInject extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new DeleteAllMethod());
        return methodList;
    }
}
  1. 在mapper中加入自定義方法
public interface UserMapper extends BaseMapper<User> {

    /**
     * 刪除全部表數據
     *
     * @return 影響行數
     */
    int deleteAll();

}
  1. test
@Test
    public void deleteAll(){
        userMapper.deleteAll();
    }

image.png

  • 附錄
  1. 參考源碼https://github.com/xiao-ren-wu/notebook/blob/master/mybatis-plus-demo-2.zip
相關文章
相關標籤/搜索