mybatis-plus也只是聽過,可是終究沒有使用過。於是自己花幾天晚上的時間研究mybatis-plus的使用。
下面的研究也是基於其官網:http://mp.baomidou.com/guide/ 。官網的介紹非常詳細。
官網有基於springboot,也有基於spring的原始方式。
MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。
0.pom.xml配置:
引入下面maven依賴之后會自動引入mybatis與mybats-spring,所以需要把原來的刪掉
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.0.1</version> </dependency>
1.前期的環境搭建工作
參考:https://baomidou.gitee.io/mybatis-plus-doc/#/install
1.1我先附上原生的mybatis整合spring以及整合pagehelper插件的xml中的配置,然后兩個做對比。
<!-- 0.連接池屬性設置讀取指定的properties文件 --> <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/> <!-- 1.將連接池放入spring容器 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--2. 配置 Mybatis的會話工廠 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 數據源 --> <property name="dataSource" ref="dataSource" /> <!-- 配置Mybatis的核心 配置文件所在位置 --> <property name="configLocation" value="classpath:SqlMapConfig.xml" /> <!-- 注意其他配置 --> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!--使用下面的方式配置參數,一行配置一個 --> <value> helperDialect=mysql reasonable=true </value> </property> </bean> </array> </property> </bean> <!-- 3.2通過MapperScannerConfigurer掃描進行批量生成代理對象 遵循規范:mapper.java和mapper.xml名字一樣且在同一個目錄下 自動掃描出來的代理對象的id為mapper類類名(首字母小寫) --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 指定掃描的包名,如果有多個,用半角逗號分隔 --> <property name="basePackage" value="cn.xm.jwxt.mapper"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean>
1.2 MP整合的配置
下面配置可以替換上面1.1中的配置。但是需要注意分頁由於是引用了MP的分頁插件,所以會導致原來pagehelper的分頁插件不生效。但是原來手寫的mapper.xml是生效的,可以說是整合成功。
<!-- 0.連接池屬性設置讀取指定的properties文件 --> <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/> <!-- 1.將連接池放入spring容器 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 配置實體掃描路徑,多個package可以用分號; 逗號, 分隔, 支持通配符*--> <!-- com.a.b.entity;com.a.c.entity;com.d.*.entity--> <property name="typeAliasesPackage" value="cn.xm.jwxt.bean.*"/> <property name="configuration" ref="mybatisConfig"/> <!-- MP 全局配置注入 --> <property name="globalConfig" ref="globalConfig"/> <property name="plugins"> <array> <!-- 分頁插件配置 --> <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"/> <!-- 性能攔截器,兼打印sql,不建議生產環境配置--> <bean id="performanceInterceptor" class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"/> </array> </property> </bean> <bean id="mybatisConfig" class="com.baomidou.mybatisplus.MybatisConfiguration"> <property name="mapUnderscoreToCamelCase" value="true"/> </bean> <!-- 定義 MP 全局策略 --> <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- 主鍵策略配置 --> <!-- 可選參數 AUTO->`0`("數據庫ID自增") INPUT->`1`(用戶輸入ID") ID_WORKER->`2`("全局唯一ID") UUID->`3`("全局唯一ID") --> <property name="idType" value="2"/> <!-- 數據庫類型配置 --> <!-- 可選參數(默認mysql) MYSQL->`mysql` ORACLE->`oracle` DB2->`db2` H2->`h2` HSQL->`hsql` SQLITE->`sqlite` POSTGRE->`postgresql` SQLSERVER2005->`sqlserver2005` SQLSERVER->`sqlserver` --> <property name="dbType" value="mysql"/> <!-- 全局表為下划線命名設置 true --> <property name="dbColumnUnderline" value="true"/> </bean> <!-- 配置mybatis 掃描mapper接口的路徑, 相當於注解@MapperScan,@MapperScan("com.baomidou.mybatisplus.test.h2.entity.mapper")--> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.xm.jwxt.mapper"/> </bean>
為了使用pageHelper的分頁插件,我們嘗試將pageHelper的分頁插件加入上面sqlsessionfactory中
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 配置實體掃描路徑,多個package可以用分號; 逗號, 分隔, 支持通配符*--> <!-- com.a.b.entity;com.a.c.entity;com.d.*.entity--> <property name="typeAliasesPackage" value="cn.xm.jwxt.bean.*"/> <property name="configuration" ref="mybatisConfig"/> <!-- MP 全局配置注入 --> <property name="globalConfig" ref="globalConfig"/> <property name="plugins"> <array> <!-- pageHelper的分頁插件配置 --> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!--使用下面的方式配置參數,一行配置一個 --> <value> helperDialect=mysql reasonable=true </value> </property> </bean> <!--MP自帶的分頁插件--> <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"/> <!-- 性能攔截器,兼打印sql,不建議生產環境配置--> <bean id="performanceInterceptor" class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"/> </array> </property> </bean>
經過證明上面的配置是可以的。也就是我們可以用原來的pagehelper插件。
而且SQL性能攔截器也生效,如下:
雖然mybatis的日志功能也可以打出SQL以及參數,但是沒有這個強大,下面是mybatis整合slf4j打出的SQL:
2.主要常見的功能簡單使用
2.1代碼生成器----逆向工程,類似於mybatis的generator
package cn.xm.jwxt.utils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.rules.DbType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.HashMap; import java.util.Map; /** * <p> * 代碼生成器演示 * </p> */ public class MpGenerator { /** * <p> * MySQL 生成演示 * </p> */ public static void main(String[] args) { AutoGenerator mpg = new AutoGenerator(); // 選擇 freemarker 引擎,默認 Veloctiy // mpg.setTemplateEngine(new FreemarkerTemplateEngine()); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir("G://MP"); gc.setFileOverride(true); gc.setActiveRecord(false);// 不需要ActiveRecord特性的請改為false gc.setEnableCache(false);// XML 二級緩存 gc.setBaseResultMap(true);// XML ResultMap gc.setBaseColumnList(false);// XML columList // .setKotlin(true) 是否生成 kotlin 代碼 gc.setAuthor("qlq"); // 自定義文件命名,注意 %s 會自動填充表實體屬性! // gc.setMapperName("%sDao"); // gc.setXmlName("%sDao"); // gc.setServiceName("MP%sService"); // gc.setServiceImplName("%sServiceDiy"); // gc.setControllerName("%sAction"); mpg.setGlobalConfig(gc); // 數據源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("sa"); dsc.setPassword("123456"); dsc.setUrl("jdbc:mysql://localhost:3306/jwxt"); mpg.setDataSource(dsc); // 策略配置 StrategyConfig strategy = new StrategyConfig(); // strategy.setCapitalMode(true);// 全局大寫命名 ORACLE 注意 strategy.setTablePrefix(new String[] { "tlog_", "tsys_" });// 此處可以修改為您的表前綴 strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略 // strategy.setInclude(new String[] { "user" }); // 需要生成的表 // strategy.setExclude(new String[]{"test"}); // 排除生成的表 // 自定義實體父類 // strategy.setSuperEntityClass("com.baomidou.demo.TestEntity"); // 自定義實體,公共字段 // strategy.setSuperEntityColumns(new String[] { "test_id", "age" }); // 自定義 mapper 父類 // strategy.setSuperMapperClass("com.baomidou.demo.TestMapper"); // 自定義 service 父類 // strategy.setSuperServiceClass("com.baomidou.demo.TestService"); // 自定義 service 實現類父類 // strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl"); // 自定義 controller 父類 // strategy.setSuperControllerClass("com.baomidou.demo.TestController"); // 【實體】是否生成字段常量(默認 false) // public static final String ID = "test_id"; // strategy.setEntityColumnConstant(true); // 【實體】是否為構建者模型(默認 false) // public User setName(String name) {this.name = name; return this;} // strategy.setEntityBuilderModel(true); mpg.setStrategy(strategy); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent("cn.xm.mapper"); pc.setModuleName("module"); mpg.setPackageInfo(pc); // 注入自定義配置,可以在 VM 中使用 cfg.abc 【可無】 InjectionConfig cfg = 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); } }; mpg.setCfg(cfg); // 自定義模板配置,可以 copy 源碼 mybatis-plus/src/main/resources/templates 下面內容修改, // 放置自己項目的 src/main/resources/templates 目錄下, 默認名稱一下可以不配置,也可以自定義模板名稱 // TemplateConfig tc = new TemplateConfig(); // tc.setController("..."); // tc.setEntity("..."); // tc.setMapper("..."); // tc.setXml("..."); // tc.setService("..."); // tc.setServiceImpl("..."); // 如上任何一個模塊如果設置 空 OR Null 將不生成該模塊。 // mpg.setTemplate(tc); // 執行生成 mpg.execute(); // 打印注入設置【可無】 System.err.println(mpg.getCfg().getMap().get("abc")); } }
下面貼出生成的代碼的結構:看的出來MP導出的時候是以模塊進行分隔的,也就是先模塊后三層架構,我習慣是先三層架構后模塊(看目錄名稱就知道對應目錄的東西),比mybatis的generator強大的是生成了對應的service目錄和web目錄,同時生成了對應的文件,都省下我們手寫了。而且也可以指定生成哪些表或者不生成哪些表。
我們查看mapper和一個文件:(沒有任何抽象方法,XML也沒有任何SQL)
package cn.xm.mapper.module.mapper; import cn.xm.mapper.module.entity.ApArrangeCourseAudit; import com.baomidou.mybatisplus.mapper.BaseMapper; /** * <p> * Mapper 接口 * </p> * * @author qlq * @since 2018-11-20 */ public interface ApArrangeCourseAuditMapper extends BaseMapper<ApArrangeCourseAudit> { }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.xm.mapper.module.mapper.ApArrangeCourseAuditMapper"> <!-- 通用查詢映射結果 --> <resultMap id="BaseResultMap" type="cn.xm.mapper.module.entity.ApArrangeCourseAudit"> <id column="audit_id" property="audit_id" /> <result column="arrange_task_id" property="arrange_task_id" /> <result column="auditor_name" property="auditor_name" /> <result column="auditor_id" property="auditor_id" /> <result column="audit_time" property="audit_time" /> <result column="audit_suggestion" property="audit_suggestion" /> <result column="audit_result" property="audit_result" /> <result column="remark" property="remark" /> </resultMap> </mapper>
查看service目錄和一個文件
package cn.xm.mapper.module.service; import cn.xm.mapper.module.entity.ApArrangeCourseAudit; import com.baomidou.mybatisplus.service.IService; /** * <p> * 服務類 * </p> * * @author qlq * @since 2018-11-20 */ public interface IApArrangeCourseAuditService extends IService<ApArrangeCourseAudit> { }
package cn.xm.mapper.module.service.impl; import cn.xm.mapper.module.entity.ApArrangeCourseAudit; import cn.xm.mapper.module.mapper.ApArrangeCourseAuditMapper; import cn.xm.mapper.module.service.IApArrangeCourseAuditService; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 服務實現類 * </p> * * @author qlq * @since 2018-11-20 */ @Service public class ApArrangeCourseAuditServiceImpl extends ServiceImpl<ApArrangeCourseAuditMapper, ApArrangeCourseAudit> implements IApArrangeCourseAuditService { }
查看web目錄以及查看文件:
package cn.xm.mapper.module.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * <p> * 前端控制器 * </p> * * @author qlq * @since 2018-11-20 */ @Controller @RequestMapping("/module/apArrangeCourseAudit") public class ApArrangeCourseAuditController { }
發現上面的控制層模板默認是SpringMVC。
上面Generator中可以設置這些的默認模板,我們可以拷貝一個出來然后進行修改
// 自定義模板配置,可以 copy 源碼 mybatis-plus/src/main/resources/templates 下面內容修改, // 放置自己項目的 src/main/resources/templates 目錄下, 默認名稱一下可以不配置,也可以自定義模板名稱 // TemplateConfig tc = new TemplateConfig(); // tc.setController("..."); // tc.setEntity("..."); // tc.setMapper("..."); // tc.setXml("..."); // tc.setService("..."); // tc.setServiceImpl("..."); // 如上任何一個模塊如果設置 空 OR Null 將不生成該模塊。 // mpg.setTemplate(tc);
查看 TemplateConfig 類:
我們再查看/template/controller.java.vm內容:
package ${package.Controller}; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; #if(${superControllerClassPackage}) import ${superControllerClassPackage}; #end /** * <p> * ${table.comment} 前端控制器 * </p> * * @author ${author} * @since ${date} */ @Controller @RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/${table.entityPath}") #if(${superControllerClass}) public class ${table.controllerName} extends ${superControllerClass} { #else public class ${table.controllerName} { #end }
看了上面源碼之后如果想修改模板就很簡單了。
2..研究MP的基本的增刪改查
實際其超類 BaseMapper 已經包括了好多成熟的方法,類似hebernatetemplate,封裝了基本的增刪改查以及查詢所有等操作。
關於其超類包裝的方法只列出接口的抽象方法,具體的實現可以參考源碼:
Dao層超類Mapper封裝的基本方法。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.baomidou.mybatisplus.mapper; import java.io.Serializable; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.session.RowBounds; public interface BaseMapper<T> { Integer insert(T var1); Integer deleteById(Serializable var1); Integer deleteByMap(@Param("cm") Map<String, Object> var1); Integer delete(@Param("ew") Wrapper<T> var1); Integer deleteBatchIds(List<? extends Serializable> var1); Integer updateById(T var1); Integer update(@Param("et") T var1, @Param("ew") Wrapper<T> var2); T selectById(Serializable var1); List<T> selectBatchIds(List<? extends Serializable> var1); List<T> selectByMap(@Param("cm") Map<String, Object> var1); T selectOne(@Param("ew") T var1); Integer selectCount(@Param("ew") Wrapper<T> var1); List<T> selectList(@Param("ew") Wrapper<T> var1); List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> var1); List<Object> selectObjs(@Param("ew") Wrapper<T> var1); List<T> selectPage(RowBounds var1, @Param("ew") Wrapper<T> var2); List<Map<String, Object>> selectMapsPage(RowBounds var1, @Param("ew") Wrapper<T> var2); }
上面的wrapper是mybatis封裝查詢條件的超類,在本版本的MP中是用EntityWrapper封裝條件。
下面研究簡單的使用:
0.環境准備:(導出一個表即可)
package cn.xm.jwxt.ceshi; import java.util.HashMap; import java.util.Map; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.rules.DbType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; /** * <p> * 代碼生成器演示 * </p> */ public class MpGenerator { /** * <p> * MySQL 生成演示 * </p> */ public static void main(String[] args) { AutoGenerator mpg = new AutoGenerator(); // 選擇 freemarker 引擎,默認 Veloctiy // mpg.setTemplateEngine(new FreemarkerTemplateEngine()); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir("G://MP"); gc.setFileOverride(true); gc.setActiveRecord(false);// 不需要ActiveRecord特性的請改為false gc.setEnableCache(false);// XML 二級緩存 gc.setBaseResultMap(true);// XML ResultMap gc.setBaseColumnList(false);// XML columList // .setKotlin(true) 是否生成 kotlin 代碼 gc.setAuthor("qlq"); // 自定義文件命名,注意 %s 會自動填充表實體屬性! // gc.setMapperName("%sDao"); // gc.setXmlName("%sDao"); // gc.setServiceName("MP%sService"); // gc.setServiceImplName("%sServiceDiy"); // gc.setControllerName("%sAction"); mpg.setGlobalConfig(gc); // 數據源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); dsc.setUrl("jdbc:mysql://localhost:3306/jwxt"); mpg.setDataSource(dsc); // 策略配置 StrategyConfig strategy = new StrategyConfig(); // strategy.setCapitalMode(true);// 全局大寫命名 ORACLE 注意 // strategy.setTablePrefix(new String[] { "tlog_", "tsys_" });// 此處可以修改為您的表前綴 // strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略 strategy.setInclude(new String[] { "user" }); // 需要生成的表 // strategy.setExclude(new String[]{"test"}); // 排除生成的表 // 自定義實體父類 // strategy.setSuperEntityClass("com.baomidou.demo.TestEntity"); // 自定義實體,公共字段 // strategy.setSuperEntityColumns(new String[] { "test_id", "age" }); // 自定義 mapper 父類 // strategy.setSuperMapperClass("com.baomidou.demo.TestMapper"); // 自定義 service 父類 // strategy.setSuperServiceClass("com.baomidou.demo.TestService"); // 自定義 service 實現類父類 // strategy.setSuperServiceImplClass("com.baomidou.demo.TestServiceImpl"); // 自定義 controller 父類 // strategy.setSuperControllerClass("com.baomidou.demo.TestController"); // 【實體】是否生成字段常量(默認 false) // public static final String ID = "test_id"; // strategy.setEntityColumnConstant(true); // 【實體】是否為構建者模型(默認 false) // public User setName(String name) {this.name = name; return this;} // strategy.setEntityBuilderModel(true); mpg.setStrategy(strategy); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent("cn.xm.jwxt"); pc.setModuleName("ceshi"); mpg.setPackageInfo(pc); // 注入自定義配置,可以在 VM 中使用 cfg.abc 【可無】 InjectionConfig cfg = 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); } }; mpg.setCfg(cfg); // 自定義模板配置,可以 copy 源碼 mybatis-plus/src/main/resources/templates 下面內容修改, // 放置自己項目的 src/main/resources/templates 目錄下, 默認名稱一下可以不配置,也可以自定義模板名稱 // TemplateConfig tc = new TemplateConfig(); // tc.setController("..."); // tc.setEntity("..."); // tc.setMapper("..."); // tc.setXml("..."); // tc.setService("..."); // tc.setServiceImpl("..."); // 如上任何一個模塊如果設置 空 OR Null 將不生成該模塊。 // mpg.setTemplate(tc); // 執行生成 mpg.execute(); // 打印注入設置【可無】 System.err.println(mpg.getCfg().getMap().get("abc")); } }
applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd "> <!-- 0.連接池屬性設置讀取指定的properties文件 --> <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/> <!-- 1.將連接池放入spring容器 --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="driverClass" value="${jdbc.driver}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 配置實體掃描路徑,多個package可以用分號; 逗號, 分隔, 支持通配符*--> <!-- com.a.b.entity;com.a.c.entity;com.d.*.entity--> <property name="typeAliasesPackage" value="cn.xm.jwxt.*"/> <property name="configuration" ref="mybatisConfig"/> <!-- MP 全局配置注入 --> <property name="globalConfig" ref="globalConfig"/> <property name="plugins"> <array> <!-- pageHelper的分頁插件配置 --> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!--使用下面的方式配置參數,一行配置一個 --> <value> helperDialect=mysql reasonable=true </value> </property> </bean> <!--MP自帶的分頁插件--> <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"/> <!-- 性能攔截器,兼打印sql,不建議生產環境配置--> <bean id="performanceInterceptor" class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"/> </array> </property> </bean> <bean id="mybatisConfig" class="com.baomidou.mybatisplus.MybatisConfiguration"> <property name="mapUnderscoreToCamelCase" value="false"/> </bean> <!-- 定義 MP 全局策略 --> <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- 主鍵策略配置 --> <!-- 可選參數 AUTO->`0`("數據庫ID自增") INPUT->`1`(用戶輸入ID") ID_WORKER->`2`("全局唯一ID") UUID->`3`("全局唯一ID") --> <property name="idType" value="1"/> <!-- 數據庫類型配置 --> <!-- 可選參數(默認mysql) MYSQL->`mysql` ORACLE->`oracle` DB2->`db2` H2->`h2` HSQL->`hsql` SQLITE->`sqlite` POSTGRE->`postgresql` SQLSERVER2005->`sqlserver2005` SQLSERVER->`sqlserver` --> <property name="dbType" value="mysql"/> <!-- 全局表為下划線命名設置 true --> <property name="dbColumnUnderline" value="false"/> </bean> <!-- 配置mybatis 掃描mapper接口的路徑, 相當於注解@MapperScan,@MapperScan("com.baomidou.mybatisplus.test.h2.entity.mapper")--> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.xm.jwxt"/> </bean> <!-- 4.配置事務管理器 --> <!-- 事務核心管理器,封裝了事務操作,依賴於連接池 --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 5.開啟注解管理aop事務 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 6.開啟注解AOP (前提是引入aop命名空間和相關jar包) --> <aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"></aop:aspectj-autoproxy> <!-- 7.開啟aop,對類代理強制使用cglib代理 --> <aop:config proxy-target-class="true"></aop:config> <!-- 8.掃描 @Service @Component 注解--> <context:component-scan base-package="cn.xm.jwxt" ></context:component-scan> </beans>
注意:對導出的表的實體,最好加上主鍵列在數據庫中的列名稱,否則調用MP自己的方法設計到主鍵操作的時候會報錯語句綁定錯誤。如下
1.測試簡單的增加:
package cn.xm.jwxt.ceshi; import java.sql.SQLException; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import cn.xm.jwxt.ceshi.entity.User; import cn.xm.jwxt.ceshi.mapper.UserMapper; /** * @Author: qlq * @Description * @Date: 22:06 2018/11/22 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:application*.xml") public class MpTest { @Autowired private UserMapper userMapper1; @Test public void test1() throws SQLException { User user = new User(); user.setUserName("username"); user.setUserID("ceshi"); user.setPassword("111222"); userMapper1.insert(user); } }
結果:
Time:581 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.insert SQL Params:['ceshi', 'username', '111222'] Execute SQL:INSERT INTO user ( userID, userName, `password` ) VALUES ( ?, ?, ? )
2.測試查詢
(0)調用MP自己的根據主鍵查詢,查詢單個和查詢多個
@Test public void test1() throws SQLException { // 查詢單個 User selectById = userMapper1.selectById("ceshi"); System.out.println(selectById); // 批量查詢 List<String> idList = new ArrayList<String>(); idList.add("ceshi"); idList.add("ceshi2"); List<User> selectBatchIds = userMapper1.selectBatchIds(idList); System.out.println(selectBatchIds); // 根據map條件查詢,map中封裝的是數據的列的條件 Map<String, Object> columnMap = new HashMap<>(); columnMap.put("userId", "ceshi"); List<User> selectByMap = userMapper1.selectByMap(columnMap); System.out.println(selectByMap); }
結果:
mybatis-plus init success.
Time:235 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectById
SQL Params:['ceshi']
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user WHERE userId=?
User [userID=ceshi, userCode=null, userName=username, password=111222, userSort=null, userStuTeaNum=null, userUnitName=null, userUnitNum=null, isUse=null, remark1=null]
Time:16 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectBatchIds
SQL Params:['ceshi', 'ceshi2']
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user WHERE userId IN ( ? , ? )
[User [userID=ceshi, userCode=null, userName=username, password=111222, userSort=null, userStuTeaNum=null, userUnitName=null, userUnitNum=null, isUse=null, remark1=null], User [userID=ceshi2, userCode=null, userName=username, password=111222, userSort=null, userStuTeaNum=null, userUnitName=null, userUnitNum=null, isUse=null, remark1=null]]
Time:20 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectByMap
SQL Params:['ceshi']
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user WHERE userId = ?
[User [userID=ceshi, userCode=null, userName=username, password=111222, userSort=null, userStuTeaNum=null, userUnitName=null, userUnitNum=null, isUse=null, remark1=null]]
(1)封裝Wrapper進行查詢:
@Test public void test1() throws SQLException { // 批量查詢 // 構造實體對應的 EntityWrapper 對象,進行過濾查詢 EntityWrapper<User> ew = new EntityWrapper<>(); ew.where("userId={0}", "ceshi").like("username", "user"); List<User> selectList = userMapper1.selectList(ew); System.out.println(selectList); }
我們查看 EntityWrapper 的源碼: (其更多的方法是封裝在其父類Wrapper中 )
/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */ package com.baomidou.mybatisplus.mapper; import com.baomidou.mybatisplus.toolkit.ReflectionKit; import com.baomidou.mybatisplus.toolkit.StringUtils; /** * <p> * Entity 對象封裝操作類,定義T-SQL語法 * </p> * * @author hubin , yanghu , Dyang , Caratacus * @Date 2016-11-7 */ @SuppressWarnings("serial") public class EntityWrapper<T> extends Wrapper<T> { /** * 拼接WHERE后應該是AND還是OR */ private String AND_OR = "AND"; /** * 數據庫表映射實體類 */ protected T entity = null; public EntityWrapper() { /* 注意,傳入查詢參數 */ } public EntityWrapper(T entity) { this.entity = entity; } public EntityWrapper(T entity, String sqlSelect) { this.entity = entity; this.sqlSelect = sqlSelect; } public T getEntity() { return entity; } public void setEntity(T entity) { this.entity = entity; } /** * <p> * 添加OR條件 * </p> * * @param sqlOr * or 條件語句 * @param params * 參數集 * @return this */ @Override public Wrapper<T> or(String sqlOr, Object... params) { if (StringUtils.isEmpty(sql.toString())) { AND_OR = "OR"; } super.or(sqlOr, params); return this; } /** * <p> * 使用OR換行,並添加一個帶()的新的條件 * </p> * <p> * eg: ew.where("name='zhangsan'").and("id=11").orNew("statu=1"); 輸出: WHERE * (name='zhangsan' AND id=11) OR (statu=1) * </p> * * @param sqlOr * AND 條件語句 * @param params * 參數值 * @return this */ @Override public Wrapper<T> orNew(String sqlOr, Object... params) { if (StringUtils.isEmpty(sql.toString())) { AND_OR = "OR"; } super.orNew(sqlOr, params); return this; } /** * SQL 片段 */ @Override public String getSqlSegment() { /* * 無條件 */ String sqlWhere = sql.toString(); if (StringUtils.isEmpty(sqlWhere)) { return null; } /* * 根據當前實體判斷是否需要將WHERE替換成 AND 增加實體不為空但所有屬性為空的情況 */ sqlWhere = ReflectionKit.checkFieldValueNotNull(entity) ? sqlWhere.replaceFirst("WHERE", AND_OR) : sqlWhere; return sqlWhere; } }
補充:wrapper還有好對條件可以使用,in、order等都可以,例如:
EntityWrapper<User> ew = new EntityWrapper<>(); ew.where("userId={0}", "ceshi").like("username", "user").in("", new ArrayList<>()).exists("") .setSqlSelect(" xx = xx").orderBy("sss", false).notIn("", new ArrayList<>());
(2)分頁查詢(實際是邏輯分頁,全部查出之后進行篩選)
// 傳一個空對象或者傳null查所有 EntityWrapper<User> ew = new EntityWrapper<>(); ew.orderBy("userId"); Integer selectCount = userMapper1.selectCount(ew); System.out.println(selectCount); List<User> selectPage = userMapper1.selectPage(new RowBounds(0, 5), ew); System.out.println(selectPage);
結果::
mybatis-plus init success.
Time:240 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectCount
SQL Params:[]
Execute SQL:SELECT COUNT(1) FROM user ORDER BY userId
8
Time:31 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectPage
SQL Params:[]
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user ORDER BY userId
Page{count=false, pageNum=1, pageSize=5, startRow=0, endRow=5, total=-1, pages=1, reasonable=false, pageSizeZero=false}
(3)查詢結果映射為Map的查詢方法:
List<Map<String, Object>> selectMaps = userMapper1.selectMaps(null); System.out.println(selectMaps); List<Map<String, Object>> selectMapsPage = userMapper1.selectMapsPage(new RowBounds(0, 5), null); System.out.println(selectMapsPage);
結果:
mybatis-plus init success.
[{userID=3c51dd8f9dc04315b97a34f9a939f3b9, userCode=2014223, isUse=1, userName=lll, userUnitNum=Soft0102, password=123456, userUnitName=軟件工程教研室111, userSort=教師}, {userID=5ea97f30d605410da4e00df52c2fedc4, userCode=院長, isUse=1, userName=院長, userUnitNum=無, password=123, userUnitName=無, userSort=教師}, {userID=a9e65788297e4a8cb68a369522ee5af7, userCode=123, isUse=1, userName=培養方案, userUnitNum=無, password=123, userUnitName=無, userSort=教師}, {userID=b33b938faada40aeac2b5ca228336473, userCode=root, isUse=1, userName=超級管理員, userUnitNum=超管, password=root, userUnitName=超管, userSort=教師}, {userID=c43aeab8a15c427e81fda9b6e55571c4, userCode=教研室主任, isUse=1, userName=教研室主任, userUnitNum=無, password=123, userUnitName=無, userSort=教師}, {userID=ceshi, userName=username, password=111222}, {userID=ceshi2, userName=username, password=111222}, {userID=e0973fd895bf4d93bd116f18512b461b, userCode=1, isUse=1, userName=1, userUnitNum=無, password=1, userUnitName=無, userSort=學生}]
Time:349 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectMaps
SQL Params:[]
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user
Page{count=false, pageNum=1, pageSize=5, startRow=0, endRow=5, total=-1, pages=1, reasonable=false, pageSizeZero=false}
Time:30 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.selectMapsPage
SQL Params:[]
Execute SQL:SELECT userId AS userID,userCode,userName,`password`,userSort,userStuTeaNum,userUnitName,userUnitNum,isUse,remark1 FROM user
3.MP進行修改
@Test public void test1() throws SQLException { // 修改單個 User entity = new User(); entity.setUserID("ceshi"); entity.setUserName("userName2"); userMapper1.updateById(entity); // 批量修改,第二個是條件 User entity2 = new User(); entity2.setPassword("8888"); Integer update = userMapper1.update(entity2, new EntityWrapper<User>()); }
查看打出的SQL:
mybatis-plus init success.
Time:236 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.updateById
SQL Params:['userName2', 'ceshi']
Execute SQL:UPDATE user SET userName=? WHERE userId=?
Time:250 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.update
SQL Params:['8888']
Execute SQL:UPDATE user SET `password`=?
4.MP進行刪除
// 刪除單個 Integer deleteById = userMapper1.deleteById("ceshi"); // 批量刪除 List<String> idList = new ArrayList<>(); idList.add("ceshi"); idList.add("ceshi2"); Integer deleteBatchIds = userMapper1.deleteBatchIds(idList); // 根據列批量刪除 Map<String, Object> condition = new HashMap<>(); condition.put("username", "username"); Integer deleteByMap = userMapper1.deleteByMap(condition); // Wrapper傳條件刪除 EntityWrapper ew = new EntityWrapper<User>(); ew.and("username={0}", "username"); Integer delete = userMapper1.delete(ew);
結果:
mybatis-plus init success.
Time:326 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.deleteById
SQL Params:['ceshi']
Execute SQL:DELETE FROM user WHERE userId=?
Time:147 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.deleteBatchIds
SQL Params:['ceshi', 'ceshi2']
Execute SQL:DELETE FROM user WHERE userId IN ( ? , ? )
Time:4 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.deleteByMap
SQL Params:['username']
Execute SQL:DELETE FROM user WHERE username = ?
Time:4 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.delete
SQL Params:[]
Execute SQL:DELETE FROM user WHERE (username='username')
3.測試自定義方法與xml寫SQL進行dao操作
與普通的mybatis開發一樣,也是接口中聲明方法,XML中寫對應的SQL
(1)mapper中聲明接口
package cn.xm.jwxt.ceshi.mapper; import cn.xm.jwxt.ceshi.entity.User; import org.apache.ibatis.annotations.Param; import com.baomidou.mybatisplus.mapper.BaseMapper; /** * <p> * Mapper 接口 * </p> * * @author qlq * @since 2018-11-24 */ public interface UserMapper extends BaseMapper<User> { public User select(@Param("id") String idString); }
(2)xml中寫SQL
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.xm.jwxt.ceshi.mapper.UserMapper"> <!-- 通用查詢映射結果 --> <resultMap id="BaseResultMap" type="cn.xm.jwxt.ceshi.entity.User"> <id column="userID" property="userID" /> <result column="userCode" property="userCode" /> <result column="userName" property="userName" /> <result column="password" property="password" /> <result column="userSort" property="userSort" /> <result column="userStuTeaNum" property="userStuTeaNum" /> <result column="userUnitName" property="userUnitName" /> <result column="userUnitNum" property="userUnitNum" /> <result column="isUse" property="isUse" /> <result column="remark1" property="remark1" /> </resultMap> <select id="select" parameterType="string" resultType="user"> select * from user where userId = #{id} </select> </mapper>
(3)測試
@Test public void test1() throws SQLException { User select = userMapper1.select("ceshi"); System.out.println(select); }
結果:
Time:440 ms - ID:cn.xm.jwxt.ceshi.mapper.UserMapper.select
SQL Params:['ceshi']
Execute SQL:select * from user where userId = ?
cn.xm.jwxt.ceshi.entity.User@1f7c1b71
補充:Springboot整合mybatisplus
(1)創建相關表並錄入數據:
DROP TABLE IF EXISTS mpUser; CREATE TABLE mpUser ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年齡', email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱', uniqueCode VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱', PRIMARY KEY (id) ); DELETE FROM mpUser; INSERT INTO mpUser (id, name, age, email, uniqueCode) VALUES (1, 'Jone', 18, 'test1@baomidou.com', "1"), (2, 'Jack', 20, 'test2@baomidou.com', "1"), (3, 'Tom', 28, 'test3@baomidou.com', "1"), (4, 'Sandy', 21, 'test4@baomidou.com', "1"), (5, 'Billie', 24, 'test5@baomidou.com', "1");
(2)pom引入
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.2</version> </dependency>
(3)application.properties引入數據源以及相關配置
############################################################ # # Mybatis settings # ############################################################ #jiazai mybatis peizhiwenjian(**代表任意目錄,*代表任意多個字符) mybatis.mapper-locations = classpath:mapper/**/*Mapper.xml mybatis.config-location = classpath:mybatis/SqlMapConfig.xml mybatis.type-aliases-package = cn.qlq.bean # mybatis-plus 字段駝峰 mybatis-plus.configuration.map-underscore-to-camel-case = false ############################################################ # # datasource settings # ############################################################ spring.datasource.driver-class-name= com.mysql.jdbc.Driver spring.datasource.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password = 123456
(4)建立實體
package cn.qlq.mybatisplus.bean; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data @TableName("mpUser") public class MpUser { private Long id; private String name; private Integer age; private String email; private String uniqueCode; }
(5)Mapper代碼:
package cn.qlq.mybatisplus.bean; import org.apache.ibatis.annotations.Mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @Mapper public interface MpUserMapper extends BaseMapper<MpUser> { }
(6)測試代碼
package daoTest; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import cn.qlq.MySpringBootApplication; import cn.qlq.mybatisplus.bean.MpUser; import cn.qlq.mybatisplus.bean.MpUserMapper; @RunWith(SpringRunner.class) @SpringBootTest(classes = MySpringBootApplication.class) public class MPTest { @Autowired private MpUserMapper mpUserMapper; @Test public void findAll() { List<MpUser> MpUser = mpUserMapper.selectList(null); System.out.println(MpUser); } }
補充:mybatis plus插件
mybatis有很多提供的有用插件,其中有用的有邏輯刪除、樂觀鎖(基於version字段實現更新,update xxx set xx= xx were version = xxx)等插件。
1.邏輯刪除插件的用法:
(1)properties配置:去掉上面的
# 駝峰命名不轉下划線
#mybatis-plus.configuration.map-underscore-to-camel-case = false
#指定XML位置
mybatis-plus.mapper-locations = classpath:mapper/**/*Mapper.xml
mybatis-plus.config-location = classpath:mybatis/SqlMapConfig.xml
# 刪除的值和未刪除的值
mybatis-plus.global-config.db-config.logic-delete-value = 1
mybatis-plus.global-config.db-config.logic-not-delete-value = 0
(2)bean增加@TableLogic注解。@TableField是為了解決表名字段駝峰轉下划線問題。
package cn.qlq.mybatisplus.bean; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data @TableName("mpUser") public class MpUser { @TableId(type = IdType.INPUT) private Long id; private String name; private Integer age; private String email; @TableField("uniqueCode") private String uniqueCode; @TableLogic private Integer deleted; }
(3)測試方法:
package daoTest; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import cn.qlq.MySpringBootApplication; import cn.qlq.mybatisplus.bean.MpUser; import cn.qlq.mybatisplus.bean.MpUserMapper; @RunWith(SpringRunner.class) @SpringBootTest(classes = MySpringBootApplication.class) public class MPTest { @Autowired private MpUserMapper mpUserMapper; @Test public void insert() { MpUser entity = null; for (long i = 1L; i < 20; i++) { entity = new MpUser(); entity.setAge(5); entity.setDeleted(0); entity.setEmail("eeeeeeeeee"); entity.setId(i); entity.setUniqueCode("ssss"); mpUserMapper.insert(entity); } } @Test public void delete() { int deleteById = mpUserMapper.deleteById(4L); System.out.println(deleteById); } @Test public void findAll() { List<MpUser> MpUser = mpUserMapper.selectList(null); System.out.println(MpUser); } }
測試增加:手動設置 Deleted 為0
(2)測試查詢:
2020/07/07-14:46:02 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.selectList ==> Preparing: SELECT id,name,age,email,uniqueCode,deleted FROM mpUser WHERE deleted=0
2020/07/07-14:46:02 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.selectList ==> Parameters:
2020/07/07-14:46:02 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.selectList <== Total: 19
(3)測試刪除:
2020/07/07-14:46:51 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.deleteById ==> Preparing: UPDATE mpUser SET deleted=1 WHERE id=? AND deleted=0
2020/07/07-14:46:51 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.deleteById ==> Parameters: 4(Long)
2020/07/07-14:46:51 [main] DEBUG cn.qlq.mybatisplus.bean.MpUserMapper.deleteById <== Updates: 1
2. SQL注入器用法:
全局配置 sqlInjector
用於注入 ISqlInjector
接口的子類,實現自定義方法注入。
如下:
/* * Copyright (c) 2011-2020, baomidou (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * https://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.core.injector; import com.baomidou.mybatisplus.core.injector.methods.*; import java.util.List; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; /** * SQL 默認注入器 * * @author hubin * @since 2018-04-10 */ public class DefaultSqlInjector extends AbstractSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { return Stream.of( new Insert(), new Delete(), new DeleteByMap(), new DeleteById(), new DeleteBatchByIds(), new Update(), new UpdateById(), new SelectById(), new SelectBatchByIds(), new SelectByMap(), new SelectOne(), new SelectCount(), new SelectMaps(), new SelectMapsPage(), new SelectObjs(), new SelectList(), new SelectPage() ).collect(toList()); } }
關於自定義全局方法攻略:參考:SelectById類。其他修改以及
/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */ package com.baomidou.mybatisplus.core.injector.methods; import com.baomidou.mybatisplus.core.enums.SqlMethod; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.scripting.defaults.RawSqlSource; /** * 根據ID 查詢一條數據 * * @author hubin * @since 2018-04-06 */ public class SelectById extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID; SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(), sqlSelectColumns(tableInfo, false), tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(), tableInfo.getLogicDeleteSql(true, true)), Object.class); return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo); } }
假設想自定義一個根據uniqueCode查詢的全局方法:
(1)Mapper中定義方法
package cn.qlq.mybatisplus.bean; import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface MyBaseMapper<T> extends BaseMapper<T> { T selectByUniqueCode(String uniqueCode); }
(2)定義SQL: (注意addSelectMappedStatementForTable方法的第二個參數要和方法名一致)
package cn.qlq.mybatisplus.bean; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.scripting.defaults.RawSqlSource; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; public class SelectByUniqueCode extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { String tableName = tableInfo.getTableName(); String sql = "SELECT * FROM %s WHERE uniqueCode=#{uniqueCode}"; SqlSource sqlSource = new RawSqlSource(configuration, String.format(sql, tableName), Object.class); return this.addSelectMappedStatementForTable(mapperClass, "selectByUniqueCode", sqlSource, tableInfo); } }
(3)注冊:
package cn.qlq.mybatisplus.bean; import java.util.List; import org.springframework.stereotype.Component; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; @Component public class MySqlInjector extends DefaultSqlInjector { /** * 如果只需增加方法,保留MP自帶方法 可以super.getMethodList() 再add * * @return */ @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); methodList.add(new SelectByUniqueCode()); return methodList; } }
(4)測試
package cn.qlq.mybatisplus.bean; import org.apache.ibatis.annotations.Mapper; @Mapper public interface MpUserMapper extends MyBaseMapper<MpUser> { }
@Test public void selectByUniqueCode() { MpUser deleteById = mpUserMapper.selectByUniqueCode("sshshshhs"); System.out.println(deleteById); }
3. mybatisplus 2.3SQL注入器用法如下:
(1)編寫SQL注入器繼承AutoSqlInjector。如果有邏輯分頁繼承LogicSqlInjector。 實際就是將xml中編寫的SQL拿到代碼中,for循環也是拼接的in sql語句。
package com.zd.bx.utils.mybatis; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.scripting.defaults.RawSqlSource; import com.baomidou.mybatisplus.entity.TableInfo; import com.baomidou.mybatisplus.mapper.AutoSqlInjector; public class MyAutoSqlInjector extends AutoSqlInjector { @Override protected void injectSql(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { super.injectSql(builderAssistant, mapperClass, modelClass, table); // 映射根據唯一編號查詢 injectSelectByUniqueCodeSql(false, mapperClass, modelClass, table); injectSelectByUniqueCodeSql(true, mapperClass, modelClass, table); // 映射根據唯一編號刪除 injectDeleteByUniqueCodeSql(false, mapperClass, modelClass, table); injectDeleteByUniqueCodeSql(true, mapperClass, modelClass, table); } /** * <p> * 注入查詢 SQL 語句 * </p> * * @param batch * 是否為批量插入 * @param mapperClass * @param modelClass * @param table */ protected void injectSelectByUniqueCodeSql(boolean batch, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { String tableName = table.getTableName(); String sql = "SELECT * FROM %s WHERE uniqueCode=#{uniqueCode}"; SqlSource sqlSource; if (batch) { String batchSql = "<script>SELECT * FROM %s WHERE uniqueCode IN (%s)</script>"; StringBuilder ids = new StringBuilder(); ids.append("\n<foreach item=\"item\" index=\"index\" collection=\"coll\" separator=\",\">"); ids.append("#{item}"); ids.append("\n</foreach>"); sqlSource = languageDriver.createSqlSource(configuration, String.format(batchSql, tableName, ids.toString()), modelClass); this.addSelectMappedStatement(mapperClass, "selectBatchUniqueCodes", sqlSource, modelClass, table); } else { sqlSource = new RawSqlSource(configuration, String.format(sql, table.getTableName()), Object.class); this.addSelectMappedStatement(mapperClass, "selectByUniqueCode", sqlSource, modelClass, table); } } /** * <p> * 注入刪除 SQL 語句 * </p> * * @param mapperClass * @param modelClass * @param table */ protected void injectDeleteByUniqueCodeSql(boolean batch, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { String sql = "<script>DELETE FROM %s WHERE uniqueCode=#{%s}</script>"; String column = "uniqueCode"; String sqlMethod = "deleteByUniqueCode"; if (batch) { sql = "<script>DELETE FROM %s WHERE uniqueCode IN (%s)</script>"; StringBuilder ids = new StringBuilder(); ids.append("\n<foreach item=\"item\" index=\"index\" collection=\"coll\" separator=\",\">"); ids.append("#{item}"); ids.append("\n</foreach>"); column = ids.toString(); sqlMethod = "deleteBatchUniqueCodes"; } String sqlFormated = String.format(sql, table.getTableName(), column); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlFormated, modelClass); this.addDeleteMappedStatement(mapperClass, sqlMethod, sqlSource); } }
(2)MybatisSqlSessionFactoryBean中設置
@Bean public MybatisSqlSessionFactoryBean sqlSessionFactoryBean() throws Exception { MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); /** * 重點,使分頁插件生效 */ // 配置數據源,此處配置為關鍵配置,如果沒有將 dynamicDataSource作為數據源則不能實現切換 sessionFactory.setDataSource(dynamicDataSource()); // 掃描Model sessionFactory.setTypeAliasesPackage("cn.qlq.bean"); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); // 掃描映射文件 sessionFactory.setMapperLocations(resolver.getResources("classpath*:mapper/**/*Mapper.xml")); GlobalConfiguration defaults = GlobalConfigUtils.defaults(); // 設置下划線為false defaults.setDbColumnUnderline(false); // 設置自定義SQL注入器 defaults.setSqlInjector(new MyAutoSqlInjector()); sessionFactory.setGlobalConfig(defaults); // 添加插件 Interceptor[] interceptors = getPlugins(); if (ArrayUtils.isNotEmpty(interceptors)) { sessionFactory.setPlugins(interceptors); } return sessionFactory; }
(3)自定義BaseMapper (@Param("coll")必須寫,因為在MyAutoSqlInjector 拼接的for循環SQL中用到了coll參數名稱)
package com.zd.bx.mapper; import java.util.Collection; import java.util.List; import org.apache.ibatis.annotations.Param; import com.baomidou.mybatisplus.mapper.BaseMapper; public interface MyBaseMapper<T> extends BaseMapper<T> { T selectByUniqueCode(String uniqueCode); List<T> selectBatchUniqueCodes(@Param("coll") Collection<String> uniqueCode); int deleteByUniqueCode(String uniqueCode); int deleteBatchUniqueCodes(@Param("coll") Collection<String> uniqueCode); }
之后的mapper繼承這個 MyBaseMapper 就可以了。
總結:用mybatis-plus進行開發的時候,對原來的功能是沒有影響的,也就是說如果一個項目原來使用的是mybatis,想使用上mybatis-plus是完全可以的。
mybatis也支持原來的mybatis逆向工程導出的xml與接口。
當然了mybatisplus之后逆向工程導出的mapper繼承BaseMapper就完全可以進行單表的增刪改查了。也就是沒有原來的mybatis逆向工程生成的xml中的SQL。原來mybatis進行單表條件查詢的時候是通過XXXExample.Criteria的方式進行查詢的。MP是通過Wrapper進行封裝查詢條件的,而且MP支持好多批量操作,有點類似HibernateTemplate。
關於MybatisPlus的配置可以參考類MybatisPlusAutoConfiguration, 這個類定義了全局配置以及SQL注入器等配置。另外一般Springboot的配置遵循默認的規約就是XXXAutoConfiguration。比如 MP的自動配置類:MybatisPlusAutoConfiguration;ActiveMQ的配置類:ActiveMQAutoConfiguration。 其對應的一般也有Properties類,比如:MybatisPlusProperties。