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(" <foreach item="item" index="index" collection="coll" separator=",">"); ids.append("#{item}"); ids.append(" </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(" <foreach item="item" index="index" collection="coll" separator=",">"); ids.append("#{item}"); ids.append(" </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。