范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

MyBatisPlus中如何使用ResultMap

  作者:字节飞扬
  原文链接:https://www.cnblogs.com/bytesfly/p/resultmap-in-mybatis-plus.html
  MyBatis-Plus (简称 MP )是一个MyBatis 的增强工具,在MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
  MyBatis-Plus 对MyBatis 基本零侵入,完全可以与MyBatis 混合使用,这点很赞。
  在涉及到关系型数据库增删查改的业务时,我比较喜欢用 MyBatis-Plus ,开发效率极高。具体的使用可以参考官网,或者自己上手摸索感受一下。
  下面简单总结一下在 MyBatis-Plus 中如何使用ResultMap 。问题说明#
  先看个例子:
  有如下两张表: create table tb_book (     id     bigint primary key,     name   varchar(32),     author varchar(20) );  create table tb_hero (     id      bigint primary key,     name    varchar(32),     age     int,     skill   varchar(32),     bid bigint );
  其中, tb_hero 中的bid 关联tb_book 表的id 。
  下面先看 Hero 实体类的代码,如下:import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter;  @Getter @Setter @NoArgsConstructor @TableName("tb_hero") @JsonInclude(JsonInclude.Include.NON_NULL) public class Hero {      @TableId("id")     private Long id;      @TableField(value = "name", keepGlobalFormat = true)     private String name;      @TableField(value = "age", keepGlobalFormat = true)     private Integer age;      @TableField(value = "skill", keepGlobalFormat = true)     private String skill;      @TableField(value = "bid", keepGlobalFormat = true)     private Long bookId;      // *********************************     // 数据库表中不存在以下字段(表join时会用到)     // *********************************      @TableField(value = "book_name", exist = false)     private String bookName;      @TableField(value = "author", exist = false)     private String author; }
  注意了,我特地把 tb_hero 表中的bid 字段映射成实体类Hero 中的bookId 属性。测试 BaseMapper 中内置的insert() 方法或者IService 中的save() 方法
  MyBatis-Plus 打印出的SQL 为:==> Preparing: INSERT INTO tb_hero ( id, "name", "age", "skill", "bid" ) VALUES ( ?, ?, ?, ?, ? ) ==> Parameters: 1589788935356416(Long), 阿飞(String), 18(Integer), 天下第一快剑(String), 1(Long)
  没毛病,  MyBatis-Plus 会根据@TableField 指定的映射关系,生成对应的SQL 。测试 BaseMapper 中内置的selectById() 方法或者IService 中的getById() 方法
  MyBatis-Plus 打印出的SQL 为:==> Preparing: SELECT id,"name","age","skill","bid" AS bookId FROM tb_hero WHERE id=? ==> Parameters: 1(Long)
  也没毛病,可以看到生成的 SELECT 中把bid 做了别名bookId 。测试自己写的SQL
  比如现在我想连接 tb_hero 与tb_book 这两张表,如下:@Mapper @Repository public interface HeroMapper extends BaseMapper {     @Select({"SELECT tb_hero.*, tb_book.name as book_name, tb_book.author" +             " FROM tb_hero" +             " LEFT JOIN tb_book" +             " ON tb_hero.bid = tb_book.id" +             " ${ew.customSqlSegment}"})     IPage pageQueryHero(@Param(Constants.WRAPPER) Wrapper queryWrapper,                               Page page); }
  查询 MyBatis-Plus 打印出的SQL 为:==> Preparing: SELECT tb_hero.*, tb_book.name AS book_name, tb_book.author FROM tb_hero LEFT JOIN tb_book ON tb_hero.bid = tb_book.id WHERE ("bid" = ?) ORDER BY id ASC LIMIT ? OFFSET ? ==> Parameters: 2(Long), 1(Long), 1(Long)
  SQL没啥问题,过滤与分页也都正常,但是此时你会发现 bookId 属性为null ,如下:
  为什么呢?
  调用 BaseMapper 中内置的selectById() 方法并没有出现这种情况啊???
  回过头来再对比一下在 HeroMapper 中自己定义的查询与MyBatis-Plus 自带的selectById() 有啥不同,还记得上面的刚刚的测试吗,生成的SQL有啥不同?
  原来, MyBatis-Plus 为BaseMapper 中内置的方法生成SQL时,会把SELECT 子句中bid 做别名bookId ,而自己写的查询MyBatis-Plus 并不会帮你修改SELECT 子句,也就导致bookId 属性为null 。解决方法#方案一:表中的字段与实体类的属性严格保持一致(字段有下划线则属性用驼峰表示)
  在这里就是 tb_hero 表中的bid 字段映射成实体类Hero 中的bid 属性。这样当然可以解决问题,但不是本篇讲的重点。方案二:把自己写的 SQL 中bid 做别名bookId 方案三:使用 @ResultMap ,这是此篇的重点
  在 @TableName 设置autoResultMap = true @TableName(value = "tb_hero", autoResultMap = true) public class Hero {      }
  然后在自定义查询中添加 @ResultMap 注解,如下:import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository;  @Mapper @Repository public interface HeroMapper extends BaseMapper {     @ResultMap("mybatis-plus_Hero")     @Select({"SELECT tb_hero.*, tb_book.name as book_name, tb_book.author" +             " FROM tb_hero" +             " LEFT JOIN tb_book" +             " ON tb_hero.bid = tb_book.id" +             " ${ew.customSqlSegment}"})     IPage pageQueryHero(@Param(Constants.WRAPPER) Wrapper queryWrapper,                               Page page); }
  这样,也能解决问题。
  下面简单看下源码, @ResultMap("mybatis-plus_实体类名") 怎么来的。
  详情见:  com.baomidou.mybatisplus.core.metadata.TableInfo#initResultMapIfNeed() /**  * 自动构建 resultMap 并注入(如果条件符合的话)  */ void initResultMapIfNeed() {     if (autoInitResultMap && null == resultMap) {         String id = currentNamespace + DOT + MYBATIS_PLUS + UNDERSCORE + entityType.getSimpleName();         List resultMappings = new ArrayList<>();         if (havePK()) {             ResultMapping idMapping = new ResultMapping.Builder(configuration, keyProperty, StringUtils.getTargetColumn(keyColumn), keyType)                 .flags(Collections.singletonList(ResultFlag.ID)).build();             resultMappings.add(idMapping);         }         if (CollectionUtils.isNotEmpty(fieldList)) {             fieldList.forEach(i -> resultMappings.add(i.getResultMapping(configuration)));         }         ResultMap resultMap = new ResultMap.Builder(configuration, id, entityType, resultMappings).build();         configuration.addResultMap(resultMap);         this.resultMap = id;     } }
  注意看上面的字符串 id 的构成,你应该可以明白。
  思考: 这种方式的 ResultMap 默认是强绑在一个@TableName 上的,如果是某个聚合查询或者查询的结果并非对应一个真实的表怎么办呢?有没有更优雅的方式?自定义@AutoResultMap注解#
  基于上面的思考,我做了下面简单的实现: 自定义@AutoResultMap注解 import java.lang.annotation.*;  /**  * 使用@AutoResultMap注解的实体类  * 自动生成{auto.mybatis-plus_类名}为id的resultMap  * {@link MybatisPlusConfig#initAutoResultMap()}  */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface AutoResultMap {  } 启动时扫描@AutoResultMap注解的实体类 package com.bytesfly.mybatis.config;  import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ReflectUtil; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; import com.bytesfly.mybatis.annotation.AutoResultMap; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement;  import javax.annotation.PostConstruct; import java.util.Set;  /**  * 可添加一些插件  */ @Configuration @EnableTransactionManagement(proxyTargetClass = true) @MapperScan(basePackages = "com.bytesfly.mybatis.mapper") @Slf4j public class MybatisPlusConfig {      @Autowired     private SqlSessionTemplate sqlSessionTemplate;      /**      * 分页插件(根据jdbcUrl识别出数据库类型, 自动选择适合该方言的分页插件)      * 相关使用说明: https://baomidou.com/guide/page.html      */     @Bean     public MybatisPlusInterceptor mybatisPlusInterceptor(DataSourceProperties dataSourceProperties) {          String jdbcUrl = dataSourceProperties.getUrl();         DbType dbType = JdbcUtils.getDbType(jdbcUrl);          MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();         interceptor.addInnerInterceptor(new PaginationInnerInterceptor(dbType));         return interceptor;     }      /**      * @AutoResultMap注解的实体类自动构建resultMap并注入      */     @PostConstruct     public void initAutoResultMap() {         try {             log.info("--- start register @AutoResultMap ---");              String namespace = "auto";              String packageName = "com.bytesfly.mybatis.model.db.resultmap";             Set> classes = ClassUtil.scanPackageByAnnotation(packageName, AutoResultMap.class);              org.apache.ibatis.session.Configuration configuration = sqlSessionTemplate.getConfiguration();              for (Class clazz : classes) {                 MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, "");                 assistant.setCurrentNamespace(namespace);                 TableInfo tableInfo = TableInfoHelper.initTableInfo(assistant, clazz);                  if (!tableInfo.isAutoInitResultMap()) {                     // 设置 tableInfo的autoInitResultMap属性 为 true                     ReflectUtil.setFieldValue(tableInfo, "autoInitResultMap", true);                     // 调用 tableInfo#initResultMapIfNeed() 方法,自动构建 resultMap 并注入                     ReflectUtil.invoke(tableInfo, "initResultMapIfNeed");                 }             }              log.info("--- finish register @AutoResultMap ---");         } catch (Throwable e) {             log.error("initAutoResultMap error", e);             System.exit(1);         }     } }
  关键代码其实没有几行,耐心看下应该不难懂。 使用@AutoResultMap注解
  还是用例子来说明更直观。
  下面是一个聚合查询: @Mapper @Repository public interface BookMapper extends BaseMapper {      @ResultMap("auto.mybatis-plus_BookAgg")     @Select({"SELECT tb_book.id, max(tb_book.name) as name, array_agg(distinct tb_hero.id order by tb_hero.id asc) as hero_ids" +             " FROM tb_hero" +             " INNER JOIN tb_book" +             " ON tb_hero.bid = tb_book.id" +             " GROUP BY tb_book.id"})     List agg(); }
  其中 BookAgg 的定义如下,在实体类上使用了@AutoResultMap 注解:@Getter @Setter @NoArgsConstructor @AutoResultMap public class BookAgg {      @TableId("id")     private Long bookId;      @TableField("name")     private String bookName;      @TableField("hero_ids")     private Object heroIds; }

1。8亿美元雇CEO,英特尔重建帝国撰文财经天下周刊作者曾广编辑董雨晴全球半导体市场火热,作为曾经最具竞争力的半导体巨头,英特尔仍旧没有走出困局。从2014年到2021年,酷睿系列芯片不断打磨14nm工艺的七年,却也特斯拉2022年04月09日新消息特斯拉特斯拉2022年04月09日新消息马斯克特斯拉可能不得不进入锂的开采马斯克特斯拉可能不得不进入锂的开采又一个里程碑!全球电动汽车保有量即将突破2000万辆全球电动汽车保有量即MQTT协议客户端开发入门指北引言Hello大家好,这里是Anyin。前段时间因为工作涉及到和硬件设备打交道,做了一些MQTT相关的工作。今天在这里也做下简单的分享。基础概念在做相关开发工作之前,我们先需要了解蔚来员工用公司服务器挖矿虚拟货币汽车沙盒安全监管持续加码来源中国经济网蔚来汽车又一次火热出圈。这一次并不是因为新能源汽车,而是虚拟货币挖矿。4月7日,证券日报记者从蔚来汽车内部发布的一项处理通报获悉,蔚来某集群服务器管理员张某利用职务之外媒声称Airbnb和eBay等网站必须采取更多措施来阻止诈骗喜剧演员兼电视节目主持人乔莱塞特(JoeLycett)表示,Airbnb和eBay等连接买家和卖家的平台必须采取更多措施保护消费者免受诈骗,他指责这些平台将收入收入囊中,但拒绝对欺2248万元!河南财政首次试行科研经费拨付直通车,保障重大科技专项实施大河网讯(记者路娇)4月8日,记者从河南省财政厅获悉,为支持打好核心技术攻坚战,大力提升我省自主创新能力,近日,省财政下达2022年首批省重大专项资金2248万元,支持高速数据中心鼓励共享停车新能源优惠江苏停车收费管理办法修订征集意见现代快报讯(记者赵丹丹)为进一步加强江苏省机动车停放服务收费管理,近日,省发展改革委会同省相关部门对江苏省机动车停放服务收费管理办法进行了修订,面向社会公开征求意见建议。现代快报记仅20开发者懂操作系统,揭晓中国基础软件开发者现状以数据库操作系统为核心的基础软件,和以芯片为核心的基础硬件,是互联互通应用系统的血脉,是动辄便使应用系统皮之不存毛将焉附的存在。在过去几十年,这一直是中国IT领域之殇,且不太受行业中国人缺乏复仇观念,这是很可怕的前几年,美国因华为公司宣布国家进入紧急状态,这在世界政治史企业史前所未有!全世界首屈一指的超级大国,因中国一家民营企业进入国家紧急状态,世界仅此一例!相信大家未必都知道其原因!但华中国量子领先世界,却有人说是假的,问题出在哪里?科技袁人关注风云之声提升思维层次导读对于任何想了解这个最重要的新科技革命的人来说,量子信息简话是最好的入门书。视频链接西瓜视频httpswww。ixigua。com708006823207中国对苹果非常重要,苹果对中国却没那么重要原因有三看破且说破曾经,苹果公司无疑是智能手机行业的霸主,其产品风靡全球,新品发布会往往是万人空巷的盛况。但是今天苹果公司早已风光不再,以降低自身售价来换取国内的市场份额。自iPhone6以后,苹果
帝欧家居卫浴和瓷砖知名品牌,并购整合效果不佳困局难以扭转独立客观第三方研究,为您筛选优质上市公司证券代码002798综合评级BBB一主营业务评分651业务分析公司过往主要是从事卫浴产品(如浴室柜坐便器浴缸淋浴器龙头等),品牌为帝王,以C伊丽莎白沃伦加密货币行业需要规则今天在CNBC上,沃伦说我不想等到一大批人,一大批小投资者,一大批小交易者被完全消灭,加密货币需要规则。沃伦的担忧是有依据的,因为许多加密货币的受害者由于勒索软件盗窃欺诈甚至是纯粹CBDC稳定币和加密货币可以颠覆传统金融主要金融评级机构穆迪将中央银行数字货币(CBDC)和稳定币列为有可能将金融老牌企业从其作为金融体系中间人主导地位的四种力量中的两种。报告称,这四种力量可以共同推动未来手机钱包使用C比特币Taproot升级遭遇激活之争Taproot,一个提议的协议升级,应该改善比特币(BTC)的隐私性和灵活性,似乎已经进入了激活之路的最后阶段,还有一个重要的步骤时引起了争论,争论的焦点是LockinOnTimeAWE告诉你选节能空调,不用担心产生昂贵电费AWE2021才结束没多久,高科技产品使我觉得眼花缭乱,有些产品没有投放到市场,概念非常高端,不过也需要更多的验证,才能完全广泛使用。很多人也在关心家电发展趋势,个人对黑科技不感冒新品亮相小米MIX新体验,让普通人能买得起的折叠屏3月29日,小米召开以生生不息为主题的新品发布会。发布会上,不少新产品和黑科技首次亮相,赚足米粉们的眼球。小米自研澎湃芯片,硅氧负极电池,液态镜头以及旗舰影像等众多新科技惊艳亮相,瓜子二手车仅需八万三,日产轩逸豪华版开回家这两年经济状况不景气,公司在当地的业务也少了很多。自从今年过完年开始,公司里的人陆陆续续被派到外地的分公司去工作,当然我也不例外。撇家舍业的为了干活都不容易。刚到一个陌生的城市的时瓜子二手车买大众POLO离婚以后照样能过得风生水起在人们的传统印象中,离婚总是一件不好的事。尤其是对女人,仿佛离婚后就开始迅速贬值,就像没了男人日子就会过得乱七八糟。我呢,离婚后第一件事就是上瓜子二手网,花6。8万买下了一辆大众P游戏手机可以当主力机?RedmiK40游戏增强版发布了相信对于喜欢打游戏的人来说,拥有一款可以专门打游戏的游戏机是一件很幸福的事情,但是,很多时候专门用来打游戏的手机都具有浮夸的杀马特风格,在日常生活中根本没办法带出门,但是专门买一个基础建设与服务能力不断完善,瓜子二手车买车当然放心要说放在五六年前,让我在网上买二手车我是万万不敢的。可是在今天,我觉得在网上买二手车比在线下实体店要放心的多。众多周知,这些年来瓜子二手车的广告简直是无处不在,还都找明星代言,看得洽洽食品(休闲食品系列三)瓜子第一品牌以单品为中心横向扩张选股理由业绩稳定增长股价不断创新高证券代码002557评级AA本文分为六部分一主营业务二公司治理三财务分析四核心竞争力及投资逻辑五盈利预测及估值六个股点评数据截止日期2020年6月