以前寫了《SpringBoot | 第九章:Mybatis-plus的集成和使用》一文,只是簡單的使用條件構造器列舉了一些通用的CURD操做。本人也想寫一篇通用的關於
mybatis-plus
的使用示例,一方面也讓本身更加了解mybatis
和mybatis-plus
,另外一方面,也由於不少新人剛入職公司時,對這塊不是很熟悉,會有一些疑惑。因此,總的來講仍是做爲一份資產,可供人查閱,這樣也能減小了不少的溝通成本。java
因此本章節,就主要來說解下關於Mybatis-plus
的不一樣場景的用法,目前主要想到的是如下幾個知識點,也是很經常使用的知識點了,後面有補充的會再啓章節來記錄的。另外,官網的文檔已經很詳盡了,你們可認真查閱下。mysql
這裏仍是以**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;
關於SpringBoot
和Mybatis-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
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方法的類。
在通用的CURD沒法知足時,這個時候 強大的條件構造器就排上用場了。主要提供了實體包裝器,用於處理 sql 拼接,排序,實體參數查詢等!
這裏須要注意:使用的是數據庫字段,不是Java屬性!,原來使用另外一款通用mapper
時記得使用的是JAVA屬性。
這也是條件構造器最靈活的地方了。
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>
類還有不少的方法,你們能夠試試。
條件參數說明
查詢方式 | 說明 |
---|---|
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") |
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結束"); }
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>
在一些須要多表關聯時,條件構造器和通用CURD都沒法知足時,還能夠自行手寫sql語句進行擴展。注意:這都是
mybatis
的用法。
如下兩種方式都是改造UserDao
接口。
@Select("SELECT * FROM USER WHERE CODE = #{userCode}") List<User> selectUserCustomParamsByAnno(@Param("userCode")String userCode);
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
默認的掃描設置爲Springboot
的VFS
實現。
直接修改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' )
本文主要列舉了開發過程當中經常使用的操做數據庫的方法及相關配置。應該能夠應付百分之八十以上的需求了吧。以後有時間,會進行補充的,好比自定義插件、大批量數據的寫法等。
若文中有錯誤或者遺漏之處,還望指出,共同進步!
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/