一篇文章瞭解mybatis-plus 3.x

MyBaits-Plus 3.X

一.簡述

1. 簡介

MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,爲簡化開發、提高效率而生。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LOJKsQJp-1575440845273)(en-resource://database/7135: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 語句以及其執行時間,建議開發測試時啓用該功能,能快速揪出慢查詢
  • 內置全局攔截插件:提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規則,預防誤操作#支持數據庫

二.快速啓動

1. Spring Boot

  1. 添加依賴
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.2.0</version>
</dependency>
  1. 配置:啓動類添加 MapperScan 註解
@SpringBootApplication
//啓動類添加此註解
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(QuickStartApplication.class, args);
    }
}
  1. 測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {

    @Resource
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        Assert.assertEquals(5, userList.size());
        userList.forEach(System.out::println);
    }
}

2. Spring MVC

  1. 添加依賴
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.2.0</version>
</dependency>
  1. 配置
  • spring配置文件中配置MapperScan
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.baomidou.mybatisplus.samples.quickstart.mapper"/>
</bean>
  • mybatis配置文件中,修改 SqlSessionFactoryMyBatis-PlusSqlSessionFactory
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
</bean>
  1. 測試
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:spring.xml"})
public class SampleTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        Assert.assertEquals(5, userList.size());
        userList.forEach(System.out::println);
    }

    @Test
    public void testSequence() {
        User u = new User();
        u.setName("Tomcat");
        u.setAge(18);
        u.setEmail("[email protected]");
        userMapper.insert(u);

        Long id1 = u.getId();
        u = new User();
        u.setName("Tomcat2");
        userMapper.insert(u);
        Assert.assertEquals("id should increase 1", id1 + 1, u.getId().longValue());
    }

    @Test
    public void testCustomizedSql() {
        System.out.println("maxAge=" + userMapper.selectMaxAge());
    }

    @Test
    public void testPagination() {
        Page<User> page = new Page<>(1, 3);
        userMapper.selectPage(page, null);
        Assert.assertTrue("total should not be 0", page.getTotal() != 0);
        for (User u : page.getRecords()) {
            System.out.println(u);
        }
        Assert.assertEquals("pagination should be 3 per page", 3, page.getRecords().size());
    }

}

三.核心功能

1. 代碼生成器

官網鏈接:代碼生成器

  1. 作用:基於模板生成代碼
  2. 支持模板類型
    • Velocity(默認)
    • Freemarker
    • Beetl
    • 自定義模板

2. CRUD接口

官網鏈接:CRUD接口

  1. mapper層接口
//1. 繼承BaseMapper,泛型中傳入這個表的實體類
//2. 在其他地方通過@Autowire注入即可
public interface UserMapper extends BaseMapper<User> {}
  1. service層接口
//1. 繼承IService,泛型中傳入這個表的實體類
//2. 在其他地方通過@Autowire注入即可
public interface UserServcie extends IService<User> {}
  1. 參數
參數 作用
T entity 保存的時候用
IPage page 分頁(需要配置分頁插件)
wrapper(條件構造器) 用於生成sql的where條件
Collection entityList 批量保存或者更新
Collection<? extends Serializable> idList 批量刪除
Map<String, Object> 查詢的時候用

3. 條件構造器

官網鏈接: 條件構造器

  1. 作用:用於生成sql的where條件
  2. api
查詢方式 說明
setSqlSelect 設置 SELECT 查詢字段
where WHERE 語句,拼接 + WHERE 條件
and AND 語句,拼接 + AND 字段=值
andNew AND 語句,拼接 + AND (字段=值)
or OR 語句,拼接 + OR 字段=值
orNew OR 語句,拼接 + OR (字段=值
eq 等於=
allEq 基於 map 內容等於=
ne 不等於<>
gt 大於>
ge 大於等於>=
lt 小於<
le 小於等於<=
like 模糊查詢 LIKE
notLike 模糊查詢 NOT LIKE
in IN 查詢
notIn NOT IN 查詢
isNull NULL 值查詢
isNotNull IS NOT NULL
groupBy 分組 GROUP BY
having HAVING 關鍵詞
orderBy 排序 ORDER BY
orderAsc ASC 排序 ORDER BY
orderDesc DESC 排序 ORDER BY
exists EXISTS 條件語句
notExists NOT EXISTS 條件語句
between BETWEEN 條件語句
notBetween NOT BETWEEN 條件語句
addFilter 自由拼接 SQL
last 拼接在最後,例如:last(“LIMIT 1”)
  1. 參數
參數 作用
boolean condition 表示該條件是否加入最後生成的sql中
R column 表示數據庫字段(String類型)
T entity 查詢的時候把entity需要查詢的字段set好,然後傳入,相當於where and and。。。
Collection entityList 批量保存或者更新
Collection<? extends Serializable> idList 批量刪除
Map<String, Object> 和實體類作用差不多
String sql 用來拼接sql
  1. 注意:
    • 不支持 rpc調用Wrapper 進行傳輸(wrapper很重,非要用可以寫dto)
    • 傳入的map或者list爲null,則不加入最後sql中
    • sql拼接有兩種:applylast ,其中last 有sql注入風險
  2. 分類
    • AbstractWrapper :QueryWrapperUpdateWrapper 的父類
    • QueryWrapper :比 AbstractWrapper 多一個 select(String... sql) 方法
    • UpdateWrapper :比 AbstractWrapper 多一個 set(String column , Object val) 方法
  3. 使用wrapper自定義sql
    1. 作用:在自定義sql中使用構造器
    2. 方式:
      1. 註解方式
      2. xml方式

4. 分頁插件

官網鏈接: 分頁插件

  1. 配置
  • spring mvc
<!-- spring xml 方式 -->
<plugins>
    <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
        <property name="sqlParser" ref="自定義解析類、可以沒有" />
        <property name="dialectClazz" value="自定義方言類、可以沒有" />
    </plugin>
</plugins>
  • spring boot

//Spring boot方式
@EnableTransactionManagement
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 設置請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求  默認false
        // paginationInterceptor.setOverflow(false);
        // 設置最大單頁限制數量,默認 500 條,-1 不受限制
        // paginationInterceptor.setLimit(500);
        return paginationInterceptor;
    }
}
  1. 使用
  • 測試類
   @Resource
    private UserMapper userMapper;
    @Test
    public void queryUserForPage(){
        IPage<User> userPage = new Page<>(2, 2);//參數一是當前頁,參數二是每頁個數
        userPage = userMapper.selectPage(userPage, null);
        List<User> list = userPage.getRecords();
        for(User user : list){
            System.out.println(user);
        }
    }
  • 向前端返回json

//----------------------包裝類,用來保存分頁需要的數據------------------------
@Data
public class UserVo {
    private Integer current;
    private Integer size;
    private Long total;
    private List<User> userList;
}
//--------------------------------Controller返回---------------------------------
   @GetMapping("queryUser")
   @ResponseBody
    public UserVo queryList(Integer current, Integer size) {
        /**
         * 這些代碼應該寫在service層
         */
        UserVo userVo = new UserVo();
        IPage<User> page = new Page<>(current, size);
        userMapper.selectPage(page, null);
        userVo.setCurrent(current);
        userVo.setSize(size);
        userVo.setTotal(page.getTotal());
        userVo.setUserList(page.getRecords());
        return userVo;
    }

5. Sequence主鍵

官網鏈接: Sequence主鍵

  1. 作用:唯一主鍵,保證全局不重複
  2. 步驟
  • 實體類添加兩個註解:@KeySequence@TableId(value = "id", type = IdType.INPUT)
    • oracle 這裏是 inputmysqlauto
@Data
@KeySequence("SEQ_USER")
public class User {
    
    @TableId(value = "id", type = IdType.INPUT)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • 添加配置
@Configuration
public class MybatisPlusConfig {
    /**
     * sequence主鍵,需要配置一個主鍵生成器
     * 配合實體類註解 {@link KeySequence} + {@link TableId} type=INPUT
     * @return
     */
    @Bean
    public H2KeyGenerator h2KeyGenerator(){
        return new H2KeyGenerator();
    }
}

四.擴展功能

1. 邏輯刪除

官網鏈接: 邏輯刪除

  1. 效果

    1. 刪除時:update user set deleted=1 where id =1 and deleted=0
    2. 查找時:select * from user where deleted=0
  2. 添加配置:如果與默認配置相同,則不需要配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1 # 邏輯已刪除值(默認爲 1)
      logic-not-delete-value: 0 # 邏輯未刪除值(默認爲 0)
  1. 實體類添加字段配置
@TableLogicprivate 
Integer deleted;

2. 自動填充

官網鏈接: 自動填充

  1. 實體類添加註解
    /**
     * 創建時間
     */
    @TableField(fill=FieldFill.INSERT)
    private Date gmtCreate;
    /**
     * 修改時間
     */
    @TableField(fill=FieldFill.INSERT_UPDATE)
    private Date gmtModified;
  1. 定義處理類
public class MybatisObjectHandler extends MetaObjectHandler{

    @Override
    public void insertFill(MetaObject metaObject) {
        //新增時填充的字段
        setFieldValByName("gmtCreate", new Date(), metaObject);
        setFieldValByName("gmtModified", new Date(), metaObject);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        //更新時 需要填充字段
        setFieldValByName("gmtModified", new Date(), metaObject);
    }
}
  1. 添加全局配置
<!----------------------------------------------xml配置------------------------------------------------->
<bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    <!--
        AUTO->`0`("數據庫ID自增")QW
         INPUT->`1`(用戶輸入ID")
        ID_WORKER->`2`("全局唯一ID")
        UUID->`3`("全局唯一ID")
    -->
    <property name="idType" value="2" />
    <property name="metaObjectHandler" ref="mybatisObjectHandler"></property>
</bean>

<bean id="mybatisObjectHandler" class="cn.lqdev.learning.mybatisplus.samples.config.MybatisObjectHandler"/>
//------------------------------------------------srpingboot配置------------------------------------------------
public MybatisSqlSessionFactoryBean sqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws IOException {
        MybatisSqlSessionFactoryBean mybatisPlus = new MybatisSqlSessionFactoryBean();

        //加載數據源
        mybatisPlus.setDataSource(dataSource);
        
        //全局配置
        GlobalConfig globalConfig  = new GlobalConfig();
        //配置填充器
        globalConfig.setMetaObjectHandler(new MetaObjectHandlerConfig());
        mybatisPlus.setGlobalConfig(globalConfig);
        
        return mybatisPlus;
    }

3. sql注入器

官網鏈接:sql注入器

  1. 創建自定義sql方法類 MyInsertAll,繼承 AbstractMethod
public class MyInsertAll extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sql = "insert into %s %s values %s";
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append(tableInfo.getKeyColumn()).append(",");
        StringBuilder valueSql = new StringBuilder();
        valueSql.append("#{").append(tableInfo.getKeyProperty()).append("},");
        tableInfo.getFieldList().forEach(x->{
            fieldSql.append(x.getColumn()).append(",");
            valueSql.append("#{").append(x.getProperty()).append("},");
        });
        fieldSql.delete(fieldSql.length()-1, fieldSql.length());
        fieldSql.insert(0, "(");
        fieldSql.append(")");
        valueSql.insert(0, "(");
        valueSql.delete(valueSql.length()-1, valueSql.length());
        valueSql.append(")");
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, String.format(sql, tableInfo.getTableName(), fieldSql.toString(), valueSql.toString()), modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "myInsertAll", sqlSource, new NoKeyGenerator(), null, null);
    }
}
  1. 創建sql注入類,繼承MyLogicSqlInjector ,並繼承 DefaultSqlInjector , 複寫 getMethodList 方法;並配置
public class MyLogicSqlInjector extends DefaultSqlInjector {

    /**
     * 如果只需增加方法,保留MP自帶方法
     * 可以super.getMethodList() 再add
     * @return
     */
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new MyInsertAll());
        return methodList;
    }
}
  1. 編寫自定義BaseMapper接口 MyBaseMapper<T> 繼承 BaseMapper<T>,添加自定義sql方法
public interface MyBaseMapper<T> extends BaseMapper<T> {
    /**
     * 自定義通用方法
     */
    int myInsertAll(T entity);
}
  1. 業務層mapper繼承自定義baseMapper MyBaseMapper
public interface UserMapper extends MyBaseMapper<User> { }
  1. 使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class DeluxeTest {
    
    @Resource
    private UserMapper mapper;

    @Test
    public void myInsertAll(){
        long id =1008888L;
        User u = new User().setEmail("[email protected]").setVersion(1).setDeleted(0).setId(id);
        mapper.myInsertAll(u);

        User user = mapper.selectById(id);
        Assert.assertNotNull(user);
        Assert.assertNotNull(user.getCreateTime());
    }
}
   

4. 動態數據源

官網鏈接:動態數據源

  1. 添加依賴
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>
  1. 添加配置
spring:
  datasource:
    dynamic:
      datasource:
        master:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
          schema: db/schema.sql
        slave_1:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
        slave_2:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver
        slave_3:
          username: sa
          password: ""
          url: jdbc:h2:mem:test
          driver-class-name: org.h2.Driver

在這裏插入圖片描述

  1. serviceImpl或者mapper接口的方法上添加依賴@DS
@Service
public class UserServiceImpl implements UserService {

  @Resource
  private UserMapper userMapper;

  //不配置,就是默認數據源
  @Override
  public void addUser(User user) {
    userMapper.addUser(user.getName(), user.getAge());
  }

  @DS("slave_1")
  @Override
  public List selectUsersFromDs() {
    return userMapper.selectUsers();
  }

  @DS("slave")
  @Override
  public List selectUserFromDsGroup() {
    return userMapper.selectUsers();
  }
}

5. ActiveRecord 模式

  • 實體類 繼承 Model類 即可使用CRUD接口
/**
 * 通用CURD示例
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
@Slf4j
public class GeneralTest {

    @Autowired
    IUserService userService;

    @Test
    public void testInsert() {
        User user = new User();
        user.setCode("001");
        user.setName("okong-insert");
        //默認的插入策略爲:FieldStrategy.NOT_NULL,即:判斷 null
        //對應在mapper.xml時寫法爲:<if test="field!=null">
        //這個可以修改的,設置字段的@TableField(strategy=FieldStrategy.NOT_EMPTY)
        //所以這個時候,爲null的字段是不會更新的,也可以開啓性能插件,查看sql語句就可以知道
        userService.insert(user);

        //新增所有字段,
        userService.insertAllColumn(user);
        log.info("新增結束");
    }

    @Test
    public void testUpdate() {

        User user = new User();
        user.setCode("101");
        user.setName("oKong-insert");
        //這就是ActiveRecord的功能
        user.insert();
        //也可以直接 userService.insert(user);

        //更新
        User updUser = new User();
        updUser.setId(user.getId());
        updUser.setName("okong-upd");

        updUser.updateById();
        log.info("更新結束");
    }

    @Test
    public void testDelete() {
        User user = new User();
        user.setCode("101");
        user.setName("oKong-delete");

        user.insert();

        //刪除
        user.deleteById();
        log.info("刪除結束");

    }

    @Test
    public void testSelect() {
        User user = new User();
        user.setCode("201");
        user.setName("oKong-selecdt");

        user.insert();

        log.info("查詢:{}",user.selectById());
    }
}

6. 樂觀鎖

官網鏈接:樂觀鎖

當要更新一條記錄的時候,希望這條記錄沒有被別人更新

樂觀鎖實現方式:

  • 取出記錄時,獲取當前version
  • 更新時,帶上這個version
  • 執行更新時, set version = newVersion where version = oldVersion
  • 如果version不對,就更新失敗
  1. 添加配置
<!--------------------------------xml方式配置--------------------------------->
<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
//--------------------------------springboot配置-----------------------------------
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}
  1. 註解實體類中代表version字段(表中也要有)
@Version
private Integer version;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章