Mybatis-Plus使用全解

前言

以前寫了《SpringBoot | 第九章:Mybatis-plus的集成和使用》一文,只是簡單的使用條件構造器列舉了一些通用的CURD操做。本人也想寫一篇通用的關於mybatis-plus的使用示例,一方面也讓本身更加了解mybatismybatis-plus,另外一方面,也由於不少新人剛入職公司時,對這塊不是很熟悉,會有一些疑惑。因此,總的來講仍是做爲一份資產,可供人查閱,這樣也能減小了不少的溝通成本。java


因此本章節,就主要來說解下關於Mybatis-plus的不一樣場景的用法,目前主要想到的是如下幾個知識點,也是很經常使用的知識點了,後面有補充的會再啓章節來記錄的。另外,官網的文檔已經很詳盡了,你們可認真查閱下。mysql

  1. 代碼生成器
  2. 通用的CURD
  3. 條件構造器
  4. 自定義SQL語句
  5. 分頁插件、性能分析插件
  6. 公共字段自動填充

工程準備

這裏仍是以**user表爲例子,數據庫爲mysql**git

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) DEFAULT NULL COMMENT '惟一標示',
  `code` varchar(20) DEFAULT NULL COMMENT '編碼',
  `name` varchar(64) DEFAULT NULL COMMENT '名稱',
  `status` char(1) DEFAULT '1' COMMENT '狀態 1啓用 0 停用',
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

關於SpringBootMybatis-plus的集成,這裏就不闡述了,這個不是今天的重點。不熟悉的同窗,可移步:http://blog.lqdev.cn/2018/07/21/springboot/chapter-nine/進行查看了解。web

代碼生成器

Mybatis-Plus已經提供了大量的自定義設置,生成的代碼徹底可以知足各種型的需求,基本覆蓋了大部分的配置了。這裏貼一個比較完整的代碼生成器類,你們可根據實際狀況進行修改。spring

MysqlGenerator.java:sql

//省略了import
public class MysqlGenerator {

    /**
     * 包名
     */
    private static final String PACKAGE_NAME = "cn.lqdev.learning.mybatisplus.samples";
    /**
     * 模塊名稱
     */
    private static final String MODULE_NAME = "biz";
    /**
     * 輸出文件的路徑
     */
    private static final String OUT_PATH = "D:\\develop\\code";
    /**
     * 代碼生成者
     */
    private static final String AUTHOR = "oKong";

    /**
     * JDBC相關配置
     */
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/learning?useUnicode=true&characterEncoding=UTF-8";
    private static final String USER_NAME = "root";
    private static final String PASSWORD = "bs";

    /**
     * <p>
     * MySQL 生成演示
     * </p>
     */
    public static void main(String[] args) {
        // 自定義須要填充的字段
        List<TableFill> tableFillList = new ArrayList<TableFill>();
        //如 每張表都有一個建立時間、修改時間
        //並且這基本上就是通用的了,新增時,建立時間和修改時間同時修改
        //修改時,修改時間會修改,
        //雖然像Mysql數據庫有自動更新幾隻,但像ORACLE的數據庫就沒有了,
        //使用公共字段填充功能,就能夠實現,自動按場景更新了。
        //以下是配置
        TableFill createField = new TableFill("gmt_create", FieldFill.INSERT); 
        TableFill modifiedField = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE); 
        tableFillList.add(createField);
        tableFillList.add(modifiedField);
        
        // 代碼生成器
        AutoGenerator mpg = new AutoGenerator().setGlobalConfig(
                // 全局配置
                new GlobalConfig().setOutputDir(OUT_PATH)// 輸出目錄
                        .setFileOverride(true)// 是否覆蓋文件
                        .setActiveRecord(true)// 開啓 activeRecord 模式
                        .setEnableCache(false)// XML 二級緩存
                        .setBaseResultMap(false)// XML ResultMap
                        .setBaseColumnList(true)// XML columList
                        .setAuthor(AUTHOR)
                        // 自定義文件命名,注意 %s 會自動填充表實體屬性!
                        .setXmlName("%sMapper").setMapperName("%sDao")
        // .setServiceName("MP%sService")
        // .setServiceImplName("%sServiceDiy")
        // .setControllerName("%sAction")
        ).setDataSource(
                // 數據源配置
                new DataSourceConfig().setDbType(DbType.MYSQL)// 數據庫類型
                        .setTypeConvert(new MySqlTypeConvert() {
                            // 自定義數據庫表字段類型轉換【可選】
                            @Override
                            public DbColumnType processTypeConvert(String fieldType) {
                                System.out.println("轉換類型:" + fieldType);
                                // if ( fieldType.toLowerCase().contains( "tinyint" ) ) {
                                // return DbColumnType.BOOLEAN;
                                // }
                                return super.processTypeConvert(fieldType);
                            }
                        }).setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL))
                .setStrategy(
                        // 策略配置
                        new StrategyConfig()
                                // .setCapitalMode(true)// 全局大寫命名
                                .setDbColumnUnderline(true)// 全局下劃線命名
                                // .setTablePrefix(new String[]{"unionpay_"})// 此處能夠修改成您的表前綴
                                .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略
                                // .setInclude(new String[] {"user"}) // 須要生成的表
                                // .setExclude(new String[]{"test"}) // 排除生成的表
                                // 自定義實體,公共字段
                                // .setSuperEntityColumns(new String[]{"test_id"})
                                .setTableFillList(tableFillList)
                                // 自定義實體父類
                                // .setSuperEntityClass("com.baomidou.demo.base.BsBaseEntity")
                                // // 自定義 mapper 父類
                                // .setSuperMapperClass("com.baomidou.demo.base.BsBaseMapper")
                                // // 自定義 service 父類
                                // .setSuperServiceClass("com.baomidou.demo.base.BsBaseService")
                                // // 自定義 service 實現類父類
                                // .setSuperServiceImplClass("com.baomidou.demo.base.BsBaseServiceImpl")
                                // 自定義 controller 父類
                                // .setSuperControllerClass("com.baomidou.demo.TestController")
                                // 【實體】是否生成字段常量(默認 false)
                                // public static final String ID = "test_id";
                                .setEntityColumnConstant(true)
                                // 【實體】是否爲構建者模型(默認 false)
                                // public User setName(String name) {this.name = name; return this;}
                                .setEntityBuilderModel(true)
                                // 【實體】是否爲lombok模型(默認 false)<a href="https://projectlombok.org/">document</a>
                                .setEntityLombokModel(true)
                // Boolean類型字段是否移除is前綴處理
                // .setEntityBooleanColumnRemoveIsPrefix(true)
                // .setRestControllerStyle(true)
                // .setControllerMappingHyphenStyle(true)
                ).setPackageInfo(
                        // 包配置
                        new PackageConfig().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)// 自定義包路徑
                                .setController("controller")// 這裏是控制器包名,默認 web
                                .setXml("mapper").setMapper("dao")

                ).setCfg(
                        // 注入自定義配置,能夠在 VM 中使用 cfg.abc 設置的值
                        new InjectionConfig() {
                            @Override
                            public void initMap() {
                                Map<String, Object> map = new HashMap<String, Object>();
                                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
                                this.setMap(map);
                            }
                        }.setFileOutConfigList(
                                Collections.<FileOutConfig>singletonList(new FileOutConfig("/templates/mapper.xml.vm") {
                                    // 自定義輸出文件目錄
                                    @Override
                                    public String outputFile(TableInfo tableInfo) {
                                        return OUT_PATH + "/xml/" + tableInfo.getEntityName() + "Mapper.xml";
                                    }
                                })))
                .setTemplate(
                        // 關閉默認 xml 生成,調整生成 至 根目錄
                        new TemplateConfig().setXml(null)
        // 自定義模板配置,模板能夠參考源碼 /mybatis-plus/src/main/resources/template 使用 copy
        // 至您項目 src/main/resources/template 目錄下,模板名稱也可自定義以下配置:
        // .setController("...");
        // .setEntity("...");
        // .setMapper("...");
        // .setXml("...");
        // .setService("...");
        // .setServiceImpl("...");
        );

        // 執行生成
        mpg.execute();
    }

}

按以上代碼生成器,生成的目錄結構以下(依賴中須要加入velocity-engine-core包,是利用模版引擎來生成的)數據庫

工程結構

對應mapper.xmlapi

對於須要自定義模版時,你們可查看官方的mybatis-plus-generate包,默認的官方模版都放在此包下。緩存

官方模版

有了代碼生成器,省了不少機械性的複製黏貼操做,還不會出錯,寫錯了再執行一次就行了!springboot

通用的CURD

MP提供了ActiveRecord的支持,因此實體類只需繼承 Model 類便可實現基本 CRUD 操做。

這裏以編寫測試類的形式,進行通用CURD操做,代碼類有相應的註釋說明。

GeneralTest.java:

/**
 * 通用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());
    }
}

以上就列舉了經常使用的,官方提供了不少的通用方法:

通用方法

注意控制檯的sql輸出,對比下就知道各方法之間的區別了。


對於通用代碼如何注入的,可查看com.baomidou.mybatisplus.mapper.AutoSqlInjector類,這個就是注入通用的CURD方法的類。

AutoSqlInjector類


條件構造器

在通用的CURD沒法知足時,這個時候 強大的條件構造器就排上用場了。主要提供了實體包裝器,用於處理 sql 拼接,排序,實體參數查詢等!

這裏須要注意:使用的是數據庫字段,不是Java屬性!,原來使用另外一款通用mapper時記得使用的是JAVA屬性。

sql條件拼接

這也是條件構造器最靈活的地方了。

ConditionTest.java

@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
@Slf4j
public class ConditionTest {
	
	@Autowired
	IUserService userService;
	
	@Test
	public void testOne() {
		User user =  new User();
		user.setCode("701");
		user.setName("okong-condition");
	    user.insert();
	    
		EntityWrapper<User> qryWrapper = new EntityWrapper<>();
		
		qryWrapper.eq(User.CODE, user.getCode());
		qryWrapper.eq(User.NAME, user.getName());
		
		//也能夠直接 
//		qryWrapper.setEntity(user);
		
		//打印sql語句
		System.out.println(qryWrapper.getSqlSegment());
		
		//設置select 字段 即:select code,name from 
		qryWrapper.setSqlSelect(User.CODE,User.NAME);
		System.out.println(qryWrapper.getSqlSelect());
		
		//查詢
	    User qryUser = userService.selectOne(qryWrapper);
	    System.out.println(qryUser);
	    log.info("拼接一結束");
	}
	
	@Test
	public void testTwo() {
		User user =  new User();
		user.setCode("702");
		user.setName("okong-condition");
	    user.insert();
	    
		EntityWrapper<User> qryWrapper = new EntityWrapper<>();
		qryWrapper.where("code = {0}", user.getCode())
		.and("name = {0}",user.getName())
		.andNew("status = 0");
		System.out.println(qryWrapper.getSqlSegment());
		//等等很複雜的。
		//複雜的建議直接寫在xml裏面了,要是非動態的話 比較xml一眼看得懂呀
		//查詢
	    User qryUser = userService.selectOne(qryWrapper);
	    System.out.println(qryUser);
	    log.info("拼接二結束");
	}

}

com.baomidou.mybatisplus.mapper.Wrapper<T>類還有不少的方法,你們能夠試試。 wrapper

條件參數說明

查詢方式 說明
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")

自定義SQL使用條件構造器

UserDao.java加入接口方法:

/**
	 * 
	 * @param rowBounds 分頁對象 直接傳入page便可
	 * @param wrapper 條件構造器
	 * @return
	 */
	List<User> selectUserWrapper(RowBounds rowBounds, @Param("ew") Wrapper<User> wrapper);

UserMapper.xml加入對應的xml節點:

<!-- 條件構造器形式 -->
	<select id="selectUserWrapper" resultType="user">
		SELECT
		<include refid="Base_Column_List" />
		FROM USER
		<where>
			${ew.sqlSegment}
		</where>
	</select>

測試類:

@Test
	public void testCustomSql() {
		User user = new User();
		user.setCode("703");
		user.setName("okong-condition");
	    user.insert();
	    
		EntityWrapper<User> qryWrapper = new EntityWrapper<>();
		qryWrapper.eq(User.CODE, user.getCode());
		
		Page<User> pageUser = new Page<>();
	    pageUser.setCurrent(1);
	    pageUser.setSize(10);
	    
	    List<User> userlist = userDao.selectUserWrapper(pageUser, qryWrapper);
	    System.out.println(userlist.get(0));
	    log.info("自定義sql結束");
	}

xml形式使用wrapper

UserDao.java

/**
	 * 
	 * @param rowBounds 分頁對象 直接傳入page便可
	 * @param wrapper 條件構造器
	 * @return
	 */
	List<User> selectUserWrapper(RowBounds rowBounds, @Param("ew") Wrapper<User> wrapper);

對應的UserMapper.xml:

<!-- 條件構造器形式 -->
	<select id="selectUserWrapper" resultType="user">
		SELECT
		<include refid="Base_Column_List" />
		FROM USER
		<where>
			${ew.sqlSegment}
		</where>
	</select>

自定義SQL語句

在一些須要多表關聯時,條件構造器和通用CURD都沒法知足時,還能夠自行手寫sql語句進行擴展。注意:這都是mybatis的用法。

如下兩種方式都是改造UserDao接口。

註解形式

@Select("SELECT * FROM USER WHERE CODE = #{userCode}")
	List<User> selectUserCustomParamsByAnno(@Param("userCode")String userCode);

xml形式

List<User> selectUserCustomParamsByXml(@Param("userCode")String userCode);

同時,UserMapper.xml新增一個節點:

<!-- 因爲設置了別名:typeAliasesPackage=cn.lqdev.learning.mybatisplus.samples.biz.entity,因此resultType能夠不寫全路徑了。 -->
    <select id="selectUserCustomParamsByXml" resultType="user">
        SELECT 
        <include refid="Base_Column_List"/> 
        FROM USER 
       WHERE CODE = #{userCode}
    </select>

測試類CustomSqlTest.java

@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
@Slf4j
public class CustomSqlTest {
	
	@Autowired
	UserDao userDao;
	
	@Test
	public void testCustomAnno() {
        User user = new User();
        user.setCode("901");
        user.setName("okong-sql");
        user.insert();
		List<User> userlist = userDao.selectUserCustomParamsByAnno(user.getCode());
		//因爲新增的 確定不爲null 故不判斷了。
		System.out.println(userlist.get(0).toString());
		log.info("註解形式結束------");
	}
	
	@Test
	public void testCustomXml() {
		User user = new User();
		user.setCode("902");
		user.setName("okong-sql");
		user.insert();
		List<User> userlist = userDao.selectUserCustomParamsByXml(user.getCode());
		//因爲新增的 確定不爲null 故不判斷了。
		System.out.println(userlist.get(0).toString());
		log.info("xml形式結束------");
	}

}

注意事項

在使用spring-boot-maven-plugin插件打包成springboot運行jar時,須要注意下,因爲springboot的jar掃描路徑方式問題,會致使別名的包未掃描到,因此這個只須要把mybatis默認的掃描設置爲SpringbootVFS實現。

直接修改spring-mybatis.xml文件:

<!--mybatis-->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
		<!-- 自動掃描mapper.xml文件,支持通配符 -->
        <property name="mapperLocations" value="classpath:mapper/**/*.xml"/>
		<!-- 配置文件,好比參數配置(是否啓動駝峯等)、插件配置等 -->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
		<!-- 啓用別名,這樣就無需寫全路徑類名了,具體可自行查閱資料 -->
        <property name="typeAliasesPackage" value="cn.lqdev.learning.mybatisplus.samples.biz.entity"/>
        <!-- MP 全局配置注入 -->
        <property name="globalConfig" ref="globalConfig"/>
        <!-- 設置vfs實現,避免路徑掃描問題 -->
        <property name="vfs"  value="com.baomidou.mybatisplus.spring.boot.starter.SpringBootVFS"></property>
    </bean>

分頁插件、性能分析插件

mybatis的插件機制使用起來是很簡單的,只須要註冊便可。

mybatis-config.xml

<plugins>
      <!-- SQL 執行性能分析,開發環境使用,線上不推薦。 -->
      <plugin interceptor="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"></plugin>
      <!-- 分頁插件配置 -->
      <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>
    </plugins>

分頁測試類(性能分析,配置後能夠輸出sql及取數時間):

@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用於測試的註解,可指定啓動類或者測試環境等,這裏直接默認。
@SpringBootTest 
@Slf4j
public class PluginTest {
	
	@Autowired
	IUserService userService;
	
	@Test
	public void testPagination() {
		Page<User> page = new Page<>();
		//每頁數
		page.setSize(10);
		//當前頁碼
		page.setCurrent(1);
		
		//無條件時
		Page<User> pageList = userService.selectPage(page);
		System.out.println(pageList.getRecords().get(0));
		
		//新增數據 避免查詢不到數據
		User user = new User();
		user.setCode("801");
		user.setName("okong-Pagination");
		user.insert();
		//加入條件構造器
		EntityWrapper<User> qryWapper = new EntityWrapper<>();
		//這裏也能直接設置 entity 這是條件就是entity的非空字段值了
//	    qryWapper.setEntity(user);
		//這裏建議直接用 常量 
	//	qryWapper.eq(User.CODE, user.getCode());
		pageList = userService.selectPage(page, qryWapper);
		System.out.println(pageList.getRecords().get(0));
		log.info("分頁結束");
	}

}

性能插件體現,控制檯輸出:

Time:4 ms - ID:cn.lqdev.learning.mybatisplus.samples.biz.dao.UserDao.selectPage
 Execute SQL: SELECT id AS id,code,`name`,`status`,gmt_create AS gmtCreate,gmt_modified AS gmtModified FROM user WHERE id=1026120705692434433 AND code='801' AND `name`='okong-Pagination' LIMIT 0,10

公共字段自動填充

一般,每一個公司都有本身的表定義,在《阿里巴巴_Java_開發手冊》中,就強制規定表必備三字段:id, gmt_create, gmt_modified。因此一般咱們都會寫個公共的攔截器去實現自動填充好比建立時間和更新時間的,無需開發人員手動設置。而在MP中就提供了這麼一個公共字段自動填充功能

設置填充字段的填充類型

User.java

/**
     * 建立時間
     */
    @TableField(fill=FieldFill.INSERT)
    private Date gmtCreate;
    /**
     * 修改時間
     */
    @TableField(fill=FieldFill.INSERT_UPDATE)
    private Date gmtModified;

注意這裏是能夠在代碼生成器裏面配置規則的,可自動配置,詳見代碼生成器類。

定義處理類

MybatisObjectHandler.java

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);
	}
}

同時修改springb-mybatis.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"/>

這個時候再新增或者修改,對應時間就會進行更新了。

Time:31 ms - ID:cn.lqdev.learning.mybatisplus.samples.biz.dao.UserDao.insert
 Execute SQL: INSERT INTO user ( id, code, `name`, gmt_create,gmt_modified ) VALUES ( 1026135016838037506, '702', 'okong-condition', '2018-08-05 23:57:07.344','2018-08-05 23:57:07.344' )

相關資料

  1. MP官網:http://mp.baomidou.com

總結

本文主要列舉了開發過程當中經常使用的操做數據庫的方法及相關配置。應該能夠應付百分之八十以上的需求了吧。以後有時間,會進行補充的,好比自定義插件、大批量數據的寫法等。

最後

若文中有錯誤或者遺漏之處,還望指出,共同進步!

老生常談

  • 我的QQ:499452441
  • 公衆號:lqdevOps

公衆號

我的博客:http://blog.lqdev.cn

原文地址:http://blog.lqdev.cn/2018/08/06/%E6%97%A5%E5%B8%B8%E7%A7%AF%E7%B4%AF/mybatis-plus-guide-one/

完整示例:https://gitee.com/oKong/mybatis-plus-samples

相關文章
相關標籤/搜索