2019独角兽企业重金招聘Python工程师标准>>>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.baomidou</groupId><artifactId>mybatisplus-spring-boot</artifactId><version>1.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.3.RELEASE</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><java.version>1.8</java.version><mybatis-plus-boot-starter.version>3.0-gamma</mybatis-plus-boot-starter.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency><!-- mybatis-plus begin --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus-boot-starter.version}</version></dependency><!-- mybatis-plus end --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

这个工程里依赖 mysql, dbcp2, gson, lombok

工程的结构

  • config.mybatis mybatis的配置
  • config.mybatis.scanner 扩展mybatis的mapper scanner
  • controller 接口控制器
  • db 访问数据库相关的对象
  • db.entity 实体
  • db.mapper mybatis mapper
  • exception 例外处理器,用来处理controller里的例外
  • repository 仓库
  • resources.mapper mybatis mapper的xml文件
  • resources.META-INF 向spring注册组件

application.yml 配置文件

#app
server:port: 8080#spring
spring:devtools:restart:enabled: false# H2 DATABASE CONFIGdatasource:type: org.apache.commons.dbcp2.BasicDataSourcedbcp2:driver-class-name: com.mysql.jdbc.Driverusername: xxxxpassword: xxxxxjmx-name: xxxxxxurl: jdbc:mysql://xxxxxx:3306/xxxxxxx?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&characterEncoding=UTF-8mybatis:mapperScanner:basePackage: com.baomidou.springboot.db.mapper*#mybatis
mybatis-plus:mapper-locations: classpath:/mapper/*Mapper.xml#实体扫描,多个package用逗号或者分号分隔typeAliasesPackage: com.baomidou.springboot.db.entitytypeEnumsPackage: com.baomidou.springboot.db.entity.enumsglobal-config:#刷新mapper 调试神器db-config:#主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";id-type: id_worker#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"field-strategy: not_empty#驼峰下划线转换column-underline: true#数据库大写下划线转换#capital-mode: true#逻辑删除配置logic-delete-value: Ylogic-not-delete-value: Ndb-type: mysqlrefresh: truesql-injector: com.baomidou.mybatisplus.extension.injector.LogicSqlInjector#自定义填充策略接口实现#meta-object-handler: com.baomidou.springboot.xxx#自定义SQL注入器#sql-injector: com.baomidou.springboot.xxxconfiguration:map-underscore-to-camel-case: truecache-enabled: false

mybatis-plus部分的配置中:

  • mapper-locations 存放mapper xml文件的位置
  • typeAliasesPackage 数据对象的目录
  • typeEnumsPackage 数据对象中使用的enum定义
  • id-type id的生成策略
  • field-strategy 字段处理策略
  • column-underline 对代码中的驼峰字段映射到数据库字段的策略
  • logic-delete-value 逻辑删除的标记值
  • logic-not-delete-value 逻辑未删除的标记值
  • sql-injector SQL注入器。 这里为了处理逻辑删除操作,使用了LogicSqlInjector注入器
  • db-type 数据库类型。支持主流的数据库
  • map-underscore-to-camel-case 数据库字段与数据对象字段的映射策略

类的说明

MybatisPlusConfig

@Configuration
public class MybatisPlusConfig {... 一些配置, 例如,配置 datasource, sqlSessionFactory, transaction manager 等等
}

MybatisPlusAutoConfiguration

@Configuration
public class MybatisPlusAutoConfiguration {/*** 将自定义的converter注册到ConversionService中** @return*/@Beanpublic ConversionService conversionService() {ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();Set<Converter> converters = new HashSet<>();converters.add(new String2SqlInjectorConverter());bean.setConverters(converters);bean.afterPropertiesSet();return bean.getObject();}/***  将String 转成 ISqlInjector 实例*/public class String2SqlInjectorConverter implements Converter<String, ISqlInjector> {@Overridepublic ISqlInjector convert(String s) {if(StringUtils.isEmpty(s))return null;try {Class clazz = ClassUtils.getClass(s);ISqlInjector sqlInjector = (ISqlInjector)clazz.newInstance();return sqlInjector;} catch (ClassNotFoundException|IllegalAccessException|InstantiationException e) {ReflectionUtils.rethrowRuntimeException(e);}return null;}}
}

向spring注册自定义的 converter,否则,application.yml中mybatis-plus.sql-injector配置会出错,提示没有相应的转换器 这个文件需要在resources/META-INF/spring.factories中注册:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.baomidou.springboot.config.mybatis.MybatisPlusAutoConfiguration

这个文件里的程序会先于spring组建bean之前执行

SuperEntity

@Data
public abstract class SuperEntity<T extends Model> extends Model<T> {/*** 主键ID , 这里故意演示注解可以无*/@TableIdprivate String  uuid;@Overrideprotected Serializable pkVal() {return this.uuid;}
}

数据库对象的父类, 在这个类中可以定义一些公共的字段。 mybatis-plus只把id作为主键字段,非id的字段,需要用@TableId来标注。pkVal() 是用来支持组合主键的,现在版本的mybatis-plus不支持组合主键

WxTokenObj

@Data
@TableName("tb_wx_token")
public class WxTokenObj extends SuperEntity<WxTokenObj>{private String token;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date createTime;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private Date modifyTime;private String accountUuid;private String name;private String avatarPath;@TableLogicprivate String isDelete;private String unionId;
}

所有的数据对象都需要继承SuperEntity, 如果表名与数据对象名称不对应,需要用@TableName标注数据表名。mybatis-plus可以配置自动解析驼峰命名的字段为下划线分割的数据库字段名。如果数据库字段名与数据字段名不一致,需要用@TableField来标注 @TableLogic标注的字段,是用来做逻辑删除的字段,在调用删除方法的时候,会将这个字段改成删除状态,而不是真正删除数据

SuperMapper

/*** 演示 mapper 父类,注意这个类不要让 mp 扫描到!!*/
public interface SuperMapper<T> extends BaseMapper<T> {// 这里可以放一些公共的方法
}

所有mapper的父接口,在这个接口中可以放一些公共方法。这个接口需要放到mapper目录外,不能让mybatis scanner 扫描到。

WxTokenMapper

public interface WxTokenMapper extends SuperMapper<WxTokenObj> {@Select("select * from tb_wx_token where uuid=#{uuid}")WxTokenObj selectOneBySQL(String uuid);WxTokenObj selectOneByWrapper(@Param("ew") Wrapper wrapper);List<WxTokenObj> selectAllTokens();
}

一个具体的mapper接口。 接口可以使用@Select等标注原生的sql,也可以使用mapper.xml 放置灵活的数据库操作。 自定义的mapper需要继承SuperMapper,也就是需要从BaseMapper中继承其定义的方法。BaseMapper中定义了很多类似JPA的自定义函数,方便开发使用:

public interface BaseMapper<T> {/*** <p>* 插入一条记录* </p>** @param entity 实体对象*/Integer insert(T entity);/*** <p>* 根据 ID 删除* </p>** @param id 主键ID*/Integer deleteById(Serializable id);/*** <p>* 根据 columnMap 条件,删除记录* </p>** @param columnMap 表字段 map 对象*/Integer deleteByMap(@Param("cm") Map<String, Object> columnMap);/*** <p>* 根据 entity 条件,删除记录* </p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/Integer delete(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 删除(根据ID 批量删除)* </p>** @param idList 主键ID列表(不能为 null 以及 empty)*/Integer deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);/*** <p>* 根据 ID 修改* </p>** @param entity 实体对象*/Integer updateById(@Param(Constants.META_OBJ_PREFIX) T entity);/*** <p>* 根据 whereEntity 条件,更新记录* </p>** @param entity        实体对象 (set 条件值,不能为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/Integer update(@Param(Constants.META_OBJ_PREFIX) T entity, @Param("ew") Wrapper<T> updateWrapper);/*** <p>* 根据 ID 查询* </p>** @param id 主键ID*/T selectById(Serializable id);/*** <p>* 查询(根据ID 批量查询)* </p>** @param idList 主键ID列表(不能为 null 以及 empty)*/List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);/*** <p>* 查询(根据 columnMap 条件)* </p>** @param columnMap 表字段 map 对象*/List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);/*** <p>* 根据 entity 条件,查询一条记录* </p>** @param queryWrapper 实体对象*/T selectOne(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 Wrapper 条件,查询总记录数* </p>** @param queryWrapper 实体对象*/Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 entity 条件,查询全部记录* </p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 Wrapper 条件,查询全部记录* </p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 Wrapper 条件,查询全部记录* 注意: 只返回第一个字段的值* </p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 entity 条件,查询全部记录(并翻页)* </p>** @param page         分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);/*** <p>* 根据 Wrapper 条件,查询全部记录(并翻页)* </p>** @param page         分页查询条件* @param queryWrapper 实体对象封装操作类*/IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
}

在定义mapper是,推荐使用idea ide + mybatisx 插件,支持从mapper 源代码 到 mapper.xml 的双向跳转、代码自动生成等。

IWxTokenRepository

仓库接口。因为仓库是用JDK proxy做增强,所有的仓库都需要单独定义接口(如果换成用cglib做增强,可以不用单独定义接口)

public interface IWxTokenRepository extends IService<WxTokenObj>{WxTokenObj getToken(String uuid);WxTokenObj getToken(Wrapper wrapper);
}

仓库接口需要继承IService接口。IService接口中定义了很多方便使用的函数(主要是与mapper对应的函数):

public interface IService<T> {/*** <p>* 插入一条记录(选择字段,策略插入)* </p>** @param entity 实体对象* @return boolean*/boolean save(T entity);/*** <p>* 插入(批量),该方法不适合 Oracle* </p>** @param entityList 实体对象集合* @return boolean*/boolean saveBatch(Collection<T> entityList);/*** <p>* 插入(批量)* </p>** @param entityList 实体对象集合* @param batchSize  插入批次数量* @return boolean*/boolean saveBatch(Collection<T> entityList, int batchSize);/*** <p>* 批量修改插入* </p>** @param entityList 实体对象集合* @return boolean*/boolean saveOrUpdateBatch(Collection<T> entityList);/*** <p>* 批量修改插入* </p>** @param entityList 实体对象集合* @param batchSize* @return boolean*/boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);/*** <p>* 根据 ID 删除* </p>** @param id 主键ID* @return boolean*/boolean removeById(Serializable id);/*** <p>* 根据 columnMap 条件,删除记录* </p>** @param columnMap 表字段 map 对象* @return boolean*/boolean removeByMap(Map<String, Object> columnMap);/*** <p>* 根据 entity 条件,删除记录* </p>** @param wrapper 实体包装类 {@link Wrapper}* @return boolean*/boolean remove(Wrapper<T> wrapper);/*** <p>* 删除(根据ID 批量删除)* </p>** @param idList 主键ID列表* @return boolean*/boolean removeByIds(Collection<? extends Serializable> idList);/*** <p>* 根据 ID 选择修改* </p>** @param entity 实体对象* @return boolean*/boolean updateById(T entity);/*** <p>* 根据 whereEntity 条件,更新记录* </p>** @param entity  实体对象* @param wrapper 实体包装类 {@link Wrapper}* @return boolean*/boolean update(T entity, Wrapper<T> wrapper);/*** <p>* 根据ID 批量更新* </p>** @param entityList 实体对象集合* @return boolean*/boolean updateBatchById(Collection<T> entityList);/*** <p>* 根据ID 批量更新* </p>** @param entityList 实体对象集合* @param batchSize  更新批次数量* @return boolean*/boolean updateBatchById(Collection<T> entityList, int batchSize);/*** <p>* TableId 注解存在更新记录,否插入一条记录* </p>** @param entity 实体对象* @return boolean*/boolean saveOrUpdate(T entity);/*** <p>* 根据 ID 查询* </p>** @param id 主键ID* @return T*/T getById(Serializable id);/*** <p>* 查询(根据ID 批量查询)* </p>** @param idList 主键ID列表* @return Collection<T>*/Collection<T> listByIds(Collection<? extends Serializable> idList);/*** <p>* 查询(根据 columnMap 条件)* </p>** @param columnMap 表字段 map 对象* @return Collection<T>*/Collection<T> listByMap(Map<String, Object> columnMap);/*** <p>* 根据 Wrapper,查询一条记录* </p>** @param wrapper 实体对象* @return T*/T getOne(Wrapper<T> wrapper);/*** <p>* 根据 Wrapper,查询一条记录* </p>** @param wrapper {@link Wrapper}* @return*/Map<String, Object> getMap(Wrapper<T> wrapper);/*** <p>* 根据 Wrapper,查询一条记录* </p>** @param wrapper {@link Wrapper}* @return Object*/Object getObj(Wrapper<T> wrapper);/*** <p>* 根据 Wrapper 条件,查询总记录数* </p>** @param wrapper 实体对象* @return int*/int count(Wrapper<T> wrapper);/*** <p>* 查询列表* </p>** @param wrapper 实体包装类 {@link Wrapper}* @return*/List<T> list(Wrapper<T> wrapper);/*** <p>* 翻页查询* </p>** @param page    翻页对象* @param wrapper 实体包装类 {@link Wrapper}* @return*/IPage<T> page(IPage<T> page, Wrapper<T> wrapper);/*** <p>* 查询列表* </p>** @param wrapper {@link Wrapper}* @return*/List<Map<String, Object>> listMaps(Wrapper<T> wrapper);/*** <p>* 根据 Wrapper 条件,查询全部记录* </p>** @param wrapper 实体对象封装操作类(可以为 null)* @return List<Object>*/List<Object> listObjs(Wrapper<T> wrapper);/*** <p>* 翻页查询* </p>** @param page    翻页对象* @param wrapper {@link Wrapper}* @return*/IPage<Map<String, Object>> pageMaps(IPage page, Wrapper<T> wrapper);}

对应的,仓库实现类也就要继承ServiceImpl,来对IService中的函数提供实现。

WxTokenRepository

仓库实现类,对自定义的仓库接口中的函数提供实现:

@Component
public class WxTokenRepository extends ServiceImpl<WxTokenMapper, WxTokenObj> implements IWxTokenRepository{public WxTokenObj getToken(String uuid) {return baseMapper.selectOneBySQL(uuid);}public WxTokenObj getToken(Wrapper wrapper) {return baseMapper.selectOneByWrapper(wrapper);}
}

在继承了ServiceImpl后,可通过baseMapper方法 接口对应的mapper。如果还需要访问其他的mapper,可以用个@Autowired 注入其他mapper。

Controller

用户接口。这里演示如何用仓库访问数据读取数据。

查询1

@GetMapping(value = "/id/{id}")public String getById(@PathVariable String id){WxTokenObj wxTokenObj = wxTokenRepository.getToken(id);return gson.toJson(wxTokenObj);}

这个接口中,访问的是mapper中使用@Select标注的数据库访问方法。可以在mapper中使用这种方式简单的定义数据库访问操作,这样的mapper函数不需要生成mapper.xml中的配置就可以实现数据操作。

查询2

@GetMapping("/token/{token}")public String getByToken(@PathVariable String token){Wrapper<WxTokenObj> wrapper = new QueryWrapper<WxTokenObj>().lambda().eq(WxTokenObj::getToken, token);WxTokenObj wxTokenObj = wxTokenRepository.getToken(wrapper);return gson.toJson(wxTokenObj);}

这个接口中,访问的是自定义的数据库访问方法。这样的mapper函数需要生成mapper.xml配置才能正确的操作数据。 为了提供查询条件,mybatis-plus提供了QueryWrapper来生成where片段。

查询3

@GetMapping("/token2/{token}")public String getByToken2(@PathVariable String token){Wrapper<WxTokenObj> wrapper = new QueryWrapper<WxTokenObj>().lambda().eq(WxTokenObj::getToken, token);WxTokenObj wxTokenObj = wxTokenRepository.selectOne(wrapper);return gson.toJson(wxTokenObj);}

这个接口中,使用的是BaseMapper中提供的数据库访问函数。这样的函数可以直接访问,不需要自己定义,也不需要在mapper.xml中配置。这种体验与JPA类似。

删除

    @DeleteMapping("/id/{id}")public String deleteById(@PathVariable String id) {boolean success = wxTokenRepository.deleteById(id);return gson.toJson(success);}

这个接口使用BaseMapper中提供的删除函数来根据ID删除数据。配置了逻辑删除后,这个删除操作只是修改了删除标记,并没有真正的删除数据。

mapper xml说明

<?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="com.baomidou.springboot.db.mapper.WxTokenMapper"><!-- 通用查询结果列 --><!--<sql id="Base_Column_List">--><!--token       ,--><!--create_time ,--><!--modify_time ,--><!--account_id  ,--><!--name        ,--><!--avatar_path ,--><!--is_delete   ,--><!--uuid        ,--><!--account_uuid,--><!--union_id--><!--</sql>--><select id="selectOneByWrapper" resultType="com.baomidou.springboot.db.entity.WxTokenObj">SELECT * FROM tb_wx_token<!-- 判断 wrapper 是否为空 emptyOfWhere --><where>${ew.sqlSegment}</where></select><select id="selectAllTokens" resultType="com.baomidou.springboot.db.entity.WxTokenObj"></select><select id="selectTokensByDeleteStatus" resultType="com.baomidou.springboot.db.entity.WxTokenObj"></select>
</mapper>

这里面的select操作的where条件,使用的是传入的Wrapper参数中的sqlSegment来实现的。Wrapper可以通过流式函数风格,以类jpa的方式定义where 条件。 mybatis-plus提供了几种Wrapper实现:

这其中有专用于查询的QueryWrapper, 专用于更新操作的UpdateWrapper。 如果需要按条件删除数据,可以用QueryWrapper传入条件。 当然,也可用根据 columnMap 条件进行查询、删除操作。 有关Wrapper的更多使用案例,可以参考mybatis-plus core里的WrapperTest.java:

private void logSqlSegment(String explain, ISqlSegment sqlSegment) {System.out.println(String.format(" ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(%s)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓", explain));System.out.println(sqlSegment.getSqlSegment());}private <T> void logParams(QueryWrapper<T> wrapper) {wrapper.getParamNameValuePairs().forEach((k, v) ->System.out.println("key: '" + k + "'\t\tvalue: '" + v + "'"));}@Testpublic void test() {Wrapper<User> wrapper = new QueryWrapper<User>().lambda().eq(User::getName, 123).or(c -> c.eq(User::getRoleId, 1).eq(User::getId, 2)).eq(User::getId, 1);log(wrapper.getSqlSegment());}@Testpublic void test1() {QueryWrapper<User> ew = new QueryWrapper<User>().eq("xxx", 123).and(i -> i.eq("andx", 65444).le("ande", 66666)).ne("xxx", 222);log(ew.getSqlSegment());ew.getParamNameValuePairs().forEach((k, v) -> System.out.println("key = " + k + " ; value = " + v));}============================================
xxx = #{ew.paramNameValuePairs.MPGENVAL1} AND ( andx = #{ew.paramNameValuePairs.MPGENVAL2} AND ande <= #{ew.paramNameValuePairs.MPGENVAL3} ) AND xxx <> #{ew.paramNameValuePairs.MPGENVAL4}
key = MPGENVAL3 ; value = 66666
key = MPGENVAL2 ; value = 65444
key = MPGENVAL1 ; value = 123
key = MPGENVAL4 ; value = 222
============================================    @Testpublic void test2() {UpdateWrapper<User> ew = new UpdateWrapper<User>().set("name", "三毛").set("id", 1).eq("xxx", 123).and(i -> i.eq("andx", 65444).le("ande", 66666)).ne("xxx", 222);log(ew.getSqlSet());log(ew.getSqlSegment());}============================================
name=#{ew.paramNameValuePairs.MPGENVAL1},id=#{ew.paramNameValuePairs.MPGENVAL2}
xxx = #{ew.paramNameValuePairs.MPGENVAL3} AND ( andx = #{ew.paramNameValuePairs.MPGENVAL4} AND ande <= #{ew.paramNameValuePairs.MPGENVAL5} ) AND xxx <> #{ew.paramNameValuePairs.MPGENVAL6}
============================================@Testpublic void test3() {UpdateWrapper<User> ew = new UpdateWrapper<User>().setSql("abc=1,def=2").eq("id", 1).ge("age", 3);log(ew.getSqlSet());log(ew.getSqlSegment());}
============================================
abc=1,def=2
id = #{ew.paramNameValuePairs.MPGENVAL1} AND age >= #{ew.paramNameValuePairs.MPGENVAL2}
============================================@Testpublic void testQueryWrapper() {logSqlSegment("去除第一个 or,以及自动拼接 and,以及手动拼接 or,以及去除最后的多个or", new QueryWrapper<User>().or().ge("age", 3).or().ge("age", 3).ge("age", 3).or().or().or().or());logSqlSegment("多个 or 相连接,去除多余的 or", new QueryWrapper<User>().ge("age", 3).or().or().or().ge("age", 3).or().or().ge("age", 3));logSqlSegment("嵌套,正常嵌套", new QueryWrapper<User>().nested(i -> i.eq("id", 1)).eq("id", 1));logSqlSegment("嵌套,第一个套外的 and 自动消除", new QueryWrapper<User>().and(i -> i.eq("id", 1)).eq("id", 1));logSqlSegment("嵌套,多层嵌套", new QueryWrapper<User>().and(i -> i.eq("id", 1).and(j -> j.eq("id", 1))));logSqlSegment("嵌套,第一个套外的 or 自动消除", new QueryWrapper<User>().or(i -> i.eq("id", 1)).eq("id", 1));logSqlSegment("嵌套,套内外自动拼接 and", new QueryWrapper<User>().eq("id", 11).and(i -> i.eq("id", 1)).eq("id", 1));logSqlSegment("嵌套,套内外手动拼接 or,去除套内第一个 or", new QueryWrapper<User>().eq("id", 11).or(i -> i.or().eq("id", 1)).or().eq("id", 1));logSqlSegment("多个 order by 和 group by 拼接,自动优化顺序,last方法拼接在最后", new QueryWrapper<User>().eq("id", 11).last("limit 1").orderByAsc("id", "name", "sex").orderByDesc("age", "txl").groupBy("id", "name", "sex").groupBy("id", "name"));logSqlSegment("只存在 order by", new QueryWrapper<User>().orderByAsc("id", "name", "sex").orderByDesc("age", "txl"));logSqlSegment("只存在 group by", new QueryWrapper<User>().groupBy("id", "name", "sex").groupBy("id", "name"));}============================================↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(去除第一个 or,以及自动拼接 and,以及手动拼接 or,以及去除最后的多个or)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
age >= #{ew.paramNameValuePairs.MPGENVAL1} OR age >= #{ew.paramNameValuePairs.MPGENVAL2} AND age >= #{ew.paramNameValuePairs.MPGENVAL3}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(多个 or 相连接,去除多余的 or)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
age >= #{ew.paramNameValuePairs.MPGENVAL1} OR age >= #{ew.paramNameValuePairs.MPGENVAL2} OR age >= #{ew.paramNameValuePairs.MPGENVAL3}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,正常嵌套)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
( id = #{ew.paramNameValuePairs.MPGENVAL1} ) AND id = #{ew.paramNameValuePairs.MPGENVAL2}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,第一个套外的 and 自动消除)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
( id = #{ew.paramNameValuePairs.MPGENVAL1} ) AND id = #{ew.paramNameValuePairs.MPGENVAL2}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,多层嵌套)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
( id = #{ew.paramNameValuePairs.MPGENVAL1} AND ( id = #{ew.paramNameValuePairs.MPGENVAL2} ) )↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,第一个套外的 or 自动消除)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
( id = #{ew.paramNameValuePairs.MPGENVAL1} ) AND id = #{ew.paramNameValuePairs.MPGENVAL2}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,套内外自动拼接 and)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
id = #{ew.paramNameValuePairs.MPGENVAL1} AND ( id = #{ew.paramNameValuePairs.MPGENVAL2} ) AND id = #{ew.paramNameValuePairs.MPGENVAL3}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(嵌套,套内外手动拼接 or,去除套内第一个 or)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
id = #{ew.paramNameValuePairs.MPGENVAL1} OR ( id = #{ew.paramNameValuePairs.MPGENVAL2} ) OR id = #{ew.paramNameValuePairs.MPGENVAL3}↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(多个 order by 和 group by 拼接,自动优化顺序,last方法拼接在最后)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
id = #{ew.paramNameValuePairs.MPGENVAL1} GROUP BY id,name,sex,id,name ORDER BY id,name,sex ASC , age,txl DESC limit 1↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(只存在 order by)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
1=1 ORDER BY id,name,sex ASC , age,txl DESC↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(只存在 group by)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
1=1 GROUP BY id,name,sex,id,name
============================================@Testpublic void testCompare() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>().allEq(getMap()).allEq((k, v) -> true, getMap()).eq("id", 1).ne("id", 1).or().gt("id", 1).ge("id", 1).lt("id", 1).le("id", 1).or().between("id", 1, 2).notBetween("id", 1, 3).like("id", 1).notLike("id", 1).or().likeLeft("id", 1).likeRight("id", 1);logSqlSegment("测试 Compare 下的方法", queryWrapper);logParams(queryWrapper);}
============================================↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(测试 Compare 下的方法)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
column1 = #{ew.paramNameValuePairs.MPGENVAL1} AND column0 = #{ew.paramNameValuePairs.MPGENVAL2} AND nullColumn IS NULL AND column1 = #{ew.paramNameValuePairs.MPGENVAL3} AND column0 = #{ew.paramNameValuePairs.MPGENVAL4} AND nullColumn IS NULL AND id = #{ew.paramNameValuePairs.MPGENVAL5} AND id <> #{ew.paramNameValuePairs.MPGENVAL6} OR id > #{ew.paramNameValuePairs.MPGENVAL7} AND id >= #{ew.paramNameValuePairs.MPGENVAL8} AND id < #{ew.paramNameValuePairs.MPGENVAL9} AND id <= #{ew.paramNameValuePairs.MPGENVAL10} OR id BETWEEN #{ew.paramNameValuePairs.MPGENVAL11} AND #{ew.paramNameValuePairs.MPGENVAL12} AND id NOT BETWEEN #{ew.paramNameValuePairs.MPGENVAL13} AND #{ew.paramNameValuePairs.MPGENVAL14} AND id LIKE #{ew.paramNameValuePairs.MPGENVAL15} AND id NOT LIKE #{ew.paramNameValuePairs.MPGENVAL16} OR id LIKE #{ew.paramNameValuePairs.MPGENVAL17} AND id LIKE #{ew.paramNameValuePairs.MPGENVAL18}
key: 'MPGENVAL3'      value: '1'
key: 'MPGENVAL2'      value: '0'
key: 'MPGENVAL1'      value: '1'
key: 'MPGENVAL18'     value: '1%'
key: 'MPGENVAL17'     value: '%1'
key: 'MPGENVAL16'     value: '%1%'
key: 'MPGENVAL15'     value: '%1%'
key: 'MPGENVAL14'     value: '3'
key: 'MPGENVAL13'     value: '1'
key: 'MPGENVAL9'      value: '1'
key: 'MPGENVAL12'     value: '2'
key: 'MPGENVAL8'      value: '1'
key: 'MPGENVAL11'     value: '1'
key: 'MPGENVAL7'      value: '1'
key: 'MPGENVAL10'     value: '1'
key: 'MPGENVAL6'      value: '1'
key: 'MPGENVAL5'      value: '1'
key: 'MPGENVAL4'      value: '0'
============================================@Testpublic void testFunc() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>()//todo in 方法是不是各个加个后缀好点.isNull("nullColumn").or().isNotNull("notNullColumn").orderByAsc("id").orderByDesc("name").groupBy("id", "name").groupBy("id2", "name2").in("inColl", getList()).or().notIn("notInColl", getList()).in("inArray").notIn("notInArray", 1, 2, 3).inSql("inSql", "1,2,3,4,5").notInSql("inSql", "1,2,3,4,5").having("sum(age) > {0}", 1).having("id is not null");logSqlSegment("测试 Func 下的方法", queryWrapper);logParams(queryWrapper);}
============================================↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(测试 Func 下的方法)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
nullColumn IS NULL OR notNullColumn IS NOT NULL AND inColl IN (#{ew.paramNameValuePairs.MPGENVAL1},#{ew.paramNameValuePairs.MPGENVAL2}) OR notInColl NOT IN (#{ew.paramNameValuePairs.MPGENVAL3},#{ew.paramNameValuePairs.MPGENVAL4}) AND notInArray NOT IN (#{ew.paramNameValuePairs.MPGENVAL5},#{ew.paramNameValuePairs.MPGENVAL6},#{ew.paramNameValuePairs.MPGENVAL7}) AND inSql IN (1,2,3,4,5) AND inSql NOT IN (1,2,3,4,5) GROUP BY id,name,id2,name2 HAVING sum(age) > #{ew.paramNameValuePairs.MPGENVAL8} AND id is not null ORDER BY id ASC , name DESC
key: 'MPGENVAL3'      value: '0'
key: 'MPGENVAL2'      value: '1'
key: 'MPGENVAL1'      value: '0'
key: 'MPGENVAL8'      value: '1'
key: 'MPGENVAL7'      value: '3'
key: 'MPGENVAL6'      value: '2'
key: 'MPGENVAL5'      value: '1'
key: 'MPGENVAL4'      value: '1'
============================================@Testpublic void testJoin() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>().last("limit 1").or().apply("date_format(column,'%Y-%m-%d') = '2008-08-08'").apply("date_format(column,'%Y-%m-%d') = {0}", LocalDate.now()).or().exists("select id from table where age = 1").or().notExists("select id from table where age = 1");logSqlSegment("测试 Join 下的方法", queryWrapper);logParams(queryWrapper);}
============================================↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(测试 Join 下的方法)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
date_format(column,'%Y-%m-%d') = '2008-08-08' AND date_format(column,'%Y-%m-%d') = #{ew.paramNameValuePairs.MPGENVAL1} OR EXISTS (select id from table where age = 1) OR NOT EXISTS (select id from table where age = 1) limit 1
key: 'MPGENVAL1'      value: '2018-08-01'
============================================@Testpublic void testNested() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>().and(i -> i.eq("id", 1).nested(j -> j.ne("id", 2))).or(i -> i.eq("id", 1).and(j -> j.ne("id", 2))).nested(i -> i.eq("id", 1).or(j -> j.ne("id", 2)));logSqlSegment("测试 Nested 下的方法", queryWrapper);logParams(queryWrapper);}============================================↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(测试 Nested 下的方法)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
( id = #{ew.paramNameValuePairs.MPGENVAL1} AND ( id <> #{ew.paramNameValuePairs.MPGENVAL2} ) ) OR ( id = #{ew.paramNameValuePairs.MPGENVAL3} AND ( id <> #{ew.paramNameValuePairs.MPGENVAL4} ) ) AND ( id = #{ew.paramNameValuePairs.MPGENVAL5} OR ( id <> #{ew.paramNameValuePairs.MPGENVAL6} ) )
key: 'MPGENVAL3'      value: '1'
key: 'MPGENVAL2'      value: '2'
key: 'MPGENVAL1'      value: '1'
key: 'MPGENVAL6'      value: '2'
key: 'MPGENVAL5'      value: '1'
key: 'MPGENVAL4'      value: '2'
============================================@Testpublic void testPluralLambda() {TableInfoHelper.initTableInfo(null, User.class);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(User::getName,"sss");queryWrapper.lambda().eq(User::getName,"sss2");logSqlSegment("测试 PluralLambda", queryWrapper);logParams(queryWrapper);}private List<Object> getList() {List<Object> list = new ArrayList<>();for (int i = 0; i < 2; i++) {list.add(i);}return list;}private Map<String, Object> getMap() {Map<String, Object> map = new HashMap<>();for (int i = 0; i < 2; i++) {map.put("column" + i, i);}map.put("nullColumn", null);return map;}

转载于:https://my.oschina.net/ez8life/blog/1922114

Spring-boot + Mybatis-plus 3.0-gamma 配置记录相关推荐

  1. Spring Boot + Mybatis多数据源和动态数据源配置

    转载自 http://blog.csdn.net/neosmith/article/details/61202084 网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种方式 ...

  2. java spring sqlite,Spring Boot+MyBatis+SQLite配置

    Spring Boot+MyBatis+SQLite配置例子参考下面 创建新项目 项目类型务必选择箭头指定的类型,否则不会自动生成代码模版 增加依赖项 junit junit 4.13.1 test ...

  3. Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置

    Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置 前言: 1. 数据库准备: 2. 环境准备: 3.代码部分 4. 测试: 5.等等 6.配合注解实现 7 .测试 ...

  4. Spring Boot+Mybatis:实现数据库登录注册与两种properties配置参数读取

    〇.参考资料 1.hutool介绍 https://blog.csdn.net/abst122/article/details/124091375 2.Spring Boot+Mybatis实现登录注 ...

  5. Eclipse + Spring boot +mybatis + mysql

    Eclipse + Spring boot +mybatis + mysql 如题.使用Springboot 2.0 版本进行网页的开发.原理和优点很多博文已经讲过了,这里不再赘述.但是很多项目按照他 ...

  6. spring boot+mybatis整合

    LZ今天自己搭建了下Spring boot+Mybatis,比原来的Spring+SpringMVC+Mybatis简单好多.其实只用Spring boot也可以开发,但是对于多表多条件分页查询,Sp ...

  7. Spring Boot + Mybatis 实现动态数据源

    动态数据源 在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库.又比如业务A要访问A数据库,业务B要访问B数据库等,都可以使用动 ...

  8. Spring boot Mybatis 整合(注解版)

    之前写过一篇关于springboot 与 mybatis整合的博文,使用了一段时间spring-data-jpa,发现那种方式真的是太爽了,mybatis的xml的映射配置总觉得有点麻烦.接口定义和映 ...

  9. Spring Boot + Mybatis 快速整合

    引言 最近在工作结束后抽时间学习了一下mybatis的知识,因为之前有学习过,但是经久不用,也未曾踏实地整理,因此有所淡忘. super meeting会议管理系统是我厂最近开发的一套会议预约平台.持 ...

  10. Spring Boot MyBatis

    MyBatis简介 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache 迁移到了google code,并且改名为MyBatis . 集成spring bo ...

最新文章

  1. next.js_Next.js手册
  2. superset的安装和使用--docker
  3. 论 MySql InnoDB 如何通过插入意向锁控制并发插入
  4. Window10设置护眼色
  5. AndroidStudio的几种依赖方式
  6. cube sdio fatfs 初始化sd卡_Stm32CubeMx配置SDIO+FATFS+FREERTOS
  7. linux 无线 网桥,基于Linux无线网桥及无线网络设备驱动分析与研究
  8. Normal Data Structure Tricks
  9. android获取ro._修改Android序列号(Serial Number)
  10. 公众号php空间是啥意思,什么是“希尔伯特空间”?
  11. Mybatis 的日志管理
  12. BZ OJ 2818 Gcd (欧拉函数)
  13. java一般安装在哪_安装Java时不知道安在哪?
  14. Linux shell:echo显示彩色字体
  15. vob文件怎么转换成mp4?
  16. HTML+CSS大作业—汽车商城-功能齐全(42页) 大学生汽车商城网页设计模板代码 网购网页作业成品 汽车商城网站设计成品
  17. Set集合的使用和知识点
  18. Java与C语言链表的不同
  19. 模型修饰在无人机航测实景三维模型生产中的应用——以DP-Modeler软件为例
  20. AS/400 初级培训课程

热门文章

  1. MongoDB 学习笔记(一)—— 安装入门
  2. SAM4E单片机之旅——22、GMAC和PHY的介绍与初始化
  3. js 自定义getClass函数实现获取dom的class 兼容火狐ie
  4. 【直线检测】【matlab】基于Hough变换的直线检测
  5. 【学堂在线数据挖掘:理论方法笔记】第二天(3.18)
  6. 基于互信息的特征选择算法MATLAB实现
  7. VS和Codeblocks安装相关
  8. GEE 导入shp数据-裁剪影像
  9. 【ArcGIS|空间分析】窗口分析
  10. word中设置论文中英文参考文献对齐方法