SweetInk / jrebel-mybatisplus

A hook plugin for Support MybatisPlus that reloads modified SQL maps.
MIT License
171 stars 32 forks source link

当Mapper类中有重载方法的时候用jrebel启动报错,而禁用本插件之后用jrebel启动则正常 #24

Open jiangjihui opened 2 years ago

jiangjihui commented 2 years ago

示例代码:

@Mapper
public interface ExamManageMapper {
    @Select("select * from exam_manage")
    List<ExamManage> findAll();

    @Select("select * from exam_manage")
    IPage<ExamManage> findAll(Page page);
}

报错内容:

Mapped Statements collection already contains value for com.exam.mapper.ExamManageMapper.findAll.
 please check com/exam/mapper/ExamManageMapper.java (best guess) and com/exam/mapper/ExamManageMapper.java (best guess)

image

SweetInk commented 2 years ago

明天验证下,不知道mybatis会不会也出现这个问题

SweetInk commented 2 years ago

使用Mybatis时,无论是否以JRebel启动都会有上面的异常,我的建议是在Mapper里最好不要使用方法重载

从源码中我们也可以知道statementId = mapper.type.name + method.name。当执行mappedStatements#put时肯定会抛出异常

  public V put(String key, V value) {
      if (containsKey(key)) {
        throw new IllegalArgumentException(name + " already contains value for " + key
            + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
      }
      if (key.contains(".")) {
        final String shortKey = getShortName(key);
        if (super.get(shortKey) == null) {
          super.put(shortKey, value);
        } else {
          super.put(shortKey, (V) new Ambiguity(shortKey));
        }
      }
      return super.put(key, value);
    }
jiangjihui commented 2 years ago

是这样的,我使用的是github上的另外一个开源项目,项目地址是:https://github.com/YXJ2018/SpringBoot-Vue-OnlineExam ,我不使用jrebel启动,或者禁用本插件之后使用jrebel启动项目都是可以的,没有报任何错误。唯独在使用本插件之后,使用jrebel启动就报上面的错误了。楼主可下载该项目的后端代码在idea启动试一下就能看出来了。

我建了一个test类,测试了下,是可以进行重载的。都可以正常执行sql image

SweetInk commented 2 years ago

是这样的,我使用的是github上的另外一个开源项目,项目地址是:https://github.com/YXJ2018/SpringBoot-Vue-OnlineExam ,我不使用jrebel启动,或者禁用本插件之后使用jrebel启动项目都是可以的,没有报任何错误。唯独在使用本插件之后,使用jrebel启动就报上面的错误了。楼主可下载该项目的后端代码在idea启动试一下就能看出来了。

我建了一个test类,测试了下,是可以进行重载的。都可以正常执行sql image

下面是MybatisPlus重写的Configuration

com.baomidou.mybatisplus.core.MybatisConfiguration#addMappedStatement

    /**
     * MybatisPlus 加载 SQL 顺序:
     * <p>1、加载XML中的SQL</p>
     * <p>2、加载sqlProvider中的SQL</p>
     * <p>3、xmlSql 与 sqlProvider不能包含相同的SQL</p>
     * <p>调整后的SQL优先级:xmlSql > sqlProvider > curdSql</p>
     */
    @Override
    public void addMappedStatement(MappedStatement ms) {
        logger.debug("addMappedStatement: " + ms.getId());
        if (mappedStatements.containsKey(ms.getId())) {
            /*
             * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
             */
            logger.error("mapper[" + ms.getId() + "] is ignored, because it exists, maybe from xml file");
            return;
        }
        super.addMappedStatement(ms);
    }

之所以关掉插件不报错,是因为这个类重写了addMappedStatement方法,如果存在相同的statement-id,直接就会忽略,而插件是对这个类进行了代理,为了实现热加载对这个方法进行了重写,即直接调用父类的addmappedStatement方法。

你关掉插件,启动项目应该会有类似的输出 c.b.m.core.MybatisConfiguration : mapper[ExamManageMapper.findAll] is ignored, because it exists, maybe from xml file

cxqweqwe commented 2 years ago

我也遇到了这个问题 我的mp版本是3.5.2

SweetInk commented 2 years ago

我也遇到了这个问题 我的mp版本是3.5.2

看我上面的回答。

yanye666 commented 1 year ago

我也遇到了这个问题 我的mp版本是3.5.2

看我上面的回答。

请问,是不修复这个问题吗,(虽然重载的写法本身就是坑)

SweetInk commented 11 months ago

我也遇到了这个问题 我的mp版本是3.5.2

看我上面的回答。

请问,是不修复这个问题吗,(虽然重载的写法本身就是坑)

目前不打算修复哦

JackTonyMa commented 9 months ago

大佬,我尝试处理了下,处理完的结果是不会reload重载的xml,正常的xml正常relaod,不会导致项目起不来,直接贴代码,看大佬是否能采纳. ctClass.addField(CtField.make("private ArrayList __ignoreMapCache = new ArrayList();", ctClass)); //rewrite addMappedStatement String bodyStatement = ""; if (null != cp.getOrNull(Constants.MybatisConfiguration$StrictMapClass)) { bodyStatement = "{ if(__ignoreMapCache.contains($1.getId())){logger.warn(\"mapper[\" + $1.getId() + \"] reload fail, maybe it was overridden\"); return; }" + " if (mappedStatements.containsKey($1.getId()) && !isCustomResource($1.getResource())&&!reloader.isReloading()) {" + " logger.warn(\"mapper[\" + $1.getId() + \"] is ignored, because it exists , maybe from xml file or override\");" + " __ignoreMapCache.add($1.getId());" + " return;" + " }" + "mappedStatements.put($1.getId(), $1);}"; }