阿里架构师万字总结:Mybatis插件实现原理,Mybatis就要这么用

从贝塞尔曲线到FFD变形 贝塞尔曲线的性质到FFD变形 与Hermite曲线通过始末两点和亮点的方向来绘制曲线不同,贝塞尔样条曲线是通过多个关键控制点构成曲线,曲线有如下良好的性质,这些性质决定了FFD最终使用贝塞尔样条曲线而非Hermite曲线。 对于给定关键点的贝塞尔曲线,曲线穿过最开始和最后的关键点 曲线的大致趋势与关键点相契合 曲线在关键点的包围之中,不会伸出到关键点以外现提出两个问题:为什么说这样的性质很契合FFD 阅读详情


mybatis中的插件,也就是拦截器interceptor,也挺有意思的。

它的简单使用,就直接拿文档中的示例来简单说下

一、使用

使用方式很简单

Copy// 使用这个注解,表明这是一个拦截器  
@Intercepts(
  // 方法签名
  {@Signature(
     // 被拦截方法所在的类
     type= Executor.class,
     // 被拦截方法名
     method = "update",
     // 被拦截方法参数列表类型
     args = {MappedStatement.class ,Object.class})}
)
 public class ExamplePlugin implements Interceptor {
     // 拦截时具体行为
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
       // implement pre-processing if needed
       Object returnObject = invocation.proceed();
       // implement post-processing if needed
       return returnObject;
     }
 }

然后如果是xml配置的话

Copy<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>

如果是 SpringBoot的话,应该是配合自动配置使用,将上面的类使用@Component注解,交由Spring容器管理,然后注册到mybatis的InterceptorChain

mybaits目前支持拦截的类和方法,有下面这些

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • StatementHandler (prepare, parameterize, batch, update, query)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultsetHandle (handleResultSets, handleOutputParameters)

二、实现原理

有可能从上面的使用猜出来它的拦截器的实现原理,那就是动态代理的方式,只不过mybatis这里并不是很直接的来使用代理,绕了个弯,于是给人感觉特别晕,也说不好这个实现是不是有些问题

就先从Executor说起吧

我们从SqlSessionFactory获取一个SqlSession时,会创建一个新的Executor实例,这个实际的创建动作在这里

org.apache.ibatis.session.Configuration#newExecutor
Copypublic Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  // 根据设置的执行器类型,创建相应类型的执行器
  executorType = executorType == null ? defaultExecutorType : executorType;
  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  Executor executor;
  if (ExecutorType.BATCH == executorType) {
    executor = new BatchExecutor(this, transaction);
  } else if (ExecutorType.REUSE == executorType) {
    executor = new ReuseExecutor(this, transaction);
  } else {
    executor = new SimpleExecutor(this, transaction);
  }
  // 如果开启了缓存,使用缓存,这里缓存执行器有点类似静态代理了
  if (cacheEnabled) {
    executor = new CachingExecutor(executor);
  }
  // 将原始执行器对象,包装下,生成一个新的执行器,代理后的对象
  executor = (Executor) interceptorChain.pluginAll(executor);
  return executor;
}

InterceptorChain是一个管家,有点类似于FilterChain,但是注意,其实差别非常的大

Copypublic class InterceptorChain {
	// 所有拦截器列表
  private final List<Interceptor> interceptors = new ArrayList<>();

  // 这里可能会是层层代理对象,一套又一套的,具体取决于拦截器的个数和被拦截的
  // 方法所在的类
  // 配置的拦截器数和每一次代理对象生成次数并不相同,会小于等于拦截器的个数
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    // 返回最后一次创建的代理对象
    return target;
  }
  // 注册拦截器的
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }
}

Interceptor是一个接口,也就是mybatis直接暴露给用户使用的需要用户实现的拦截器接口

Copypublic interface Interceptor {
   // 实现类填充自己的逻辑,参数为Invocation,
  Object intercept(Invocation invocation) throws Throwable;

   // 默认方法,创建代理对象
  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
   // 实现类去做些事情
  default void setProperties(Properties properties) {
    // NOP
  }

}

着重看下一这个

Copy// 首先这是一个Jdk动态代理的InvocationHandler实现类
public class Plugin implements InvocationHandler {

  private final Object target;
  private final Interceptor interceptor;
  private final Map<Class<?>, Set<Method>> signatureMap;

  private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }
  // 静态方法,用来直接创建代理对象
  public static Object wrap(Object target, Interceptor interceptor) {
    // 获取当前拦截器需要被拦截的所有的方法
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    // 获取被代理对象的Class
    Class<?> type = target.getClass();
    // 把被代理对象所有能在签名Map中找到的直接实现的接口和祖先接口,查找出来
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    // 找到了就创建代理对象
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          // 创建一个InvocationHandler实例
          new Plugin(target, interceptor, signatureMap));
    }
    // 没找到 就返回
    // 这个对象不一定说一个未经代理过的对象,也可能是代理过的
    return target;
  }

  // 当调用这个代理对象的任何方法时,调用此方法
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // 首先找下当前被调用的这个方法所在的类,被拦截的所有的方法 
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        // 如果当前被调用的方法是需要被拦截的,那么就执行我们自定义的拦截逻辑
        // interceptor是我们自定义的拦截器,在我们自定义的拦截器里,需要获取到
        // 原委托对象,被调用的方法,以及参数,这里做了很好的封装,将用户的使用和
        // 具体的实现,做了一个完全的分离,用户感知不到任何具体的实现
        // Invocation#proceed 就做了一件事 method.invoke(target,args);
        return interceptor.intercept(new Invocation(target, method, args));
      }
      // 如果当前被调用的方法没有被拦截,那么直接调用原方法
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

  // 获取拦截器指定的被拦截方法的方法签名
  // key是被拦截方法的返回值类型
  private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    // 获取注解 @Intercepts信息
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251 避免出现没有具体的拦截信息的情况
    if (interceptsAnnotation == null) {
      throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    // 获取配置的被拦截方法的签名信息
    Signature[] sigs = interceptsAnnotation.value();
    Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
    // 统统放到Map
    for (Signature sig : sigs) {
      Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
      try {
        // 将定义构建成实际的Method对象
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }
  // 获取被代理对象所有的接口信息
  private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
    Set<Class<?>> interfaces = new HashSet<>();
    while (type != null) {
      for (Class<?> c : type.getInterfaces()) {
        if (signatureMap.containsKey(c)) {
          // 如果被代理类接口和返回值类型一致,接口加进来
          interfaces.add(c);
        }
      }
      // 找到被代理类的父类,然后继续查找接口信息
      type = type.getSuperclass();
    }
    return interfaces.toArray(new Class<?>[interfaces.size()]);
  }
}

到这里就说完了mybatis插件的实现原理

整体实现其实也很简单,我们想给那个类的哪个方法拦截一下,把实现拦截器,然后配置下要拦截的信息,之后mybatis给我们生成一个动态代理对象,就可以了。

下面我们以具体案例来更加深刻的认识理解其实现原理

三、加强理解

我们使用具体的案例,来走一遍

1. Case 1

①. 单拦截器单拦截方法

Copy@Intercepts(
  {@Signature(
     type= Executor.class,
     method = "update",
     args = {MappedStatement.class ,Object.class})}
)
 public class ExamplePlugin implements Interceptor {
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
       System.out.println("before execute update");
       Object returnObject = invocation.proceed();
       System.out.println("after  execute update");
       return returnObject;
     }
 }

假设目前我们就设置了这么一个拦截器

那么就会生成一个CachingExecutor的代理对象,我们假设代理对象的全限定名是com.sun.proxy.$Proxy0,并且这个对象对象是implements Executor的

这时调用代理对象的update方法调用栈如下

mybatis-plugin

2. Case 2

①. 单拦截器多拦截方法

假设有个需求需要给StatementHandler的update增加点一样的拦截逻辑

Copy@Intercepts(
  {@Signature(
     type= Executor.class,
     method = "update",
     args = {MappedStatement.class ,Object.class})},
  {@Signature(
     type= StatementHandler.class,
     method = "update",
     args = {Statement.class})}
)
 public class ExamplePlugin implements Interceptor {
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
       System.out.println("before execute update");
       Object returnObject = invocation.proceed();
       System.out.println("after  execute update");
       return returnObject;
     }
 }

同样是获取执行器的逻辑,这个时候我们得到的代理后的对象不会是同时实现了Executor 和StatementHandler接口的,只能实现Executor接口,因为这个

Copy// 这个时候type为 CachingExecutor
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
  Set<Class<?>> interfaces = new HashSet<>();
  while (type != null) {
    // type的接口Executor显然是在Map中的
    for (Class<?> c : type.getInterfaces()) {
      // 仅允许对接口为Executor的实例做代理,因为代理后的类一定得是一个Executor的实现类
      if (signatureMap.containsKey(c)) {
        interfaces.add(c);
      }
    }
    type = type.getSuperclass();
  }
  // 最终也就只能找到Executor这么一个接口了
  return interfaces.toArray(new Class<?>[interfaces.size()]);
}

这种情况下就和上面一样了

区别在于,如果我们需要创建一个StatementHandler的实例时,代理对象就会变成StatementHandler的实现类实例了

Copypublic StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  // 被拦截器增强后的代理对象StatementHandler
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

3. Case 3

多拦截器单拦截方法

如果有多个拦截器呢?

Copy@Intercepts(
  {@Signature(
     type= Executor.class,
     method = "update",
     args = {MappedStatement.class ,Object.class})}
)
 public class ExamplePluginA implements Interceptor {
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
       System.out.println("before execute update");
       Object returnObject = invocation.proceed();
       System.out.println("after  execute update");
       return returnObject;
     }
 }

@Intercepts(
  {@Signature(
     type= Executor.class,
     method = "flushStatements",
     args = {})}
)
 public class ExamplePluginB implements Interceptor {
     @Override
     public Object intercept(Invocation invocation) throws Throwable {
       System.out.println("before execute flushStatements");
       Object returnObject = invocation.proceed();
       System.out.println("after  execute flushStatements");
       return returnObject;
     }
 }

上面有两个拦截器,会出现代理对象成为委托对象的情况,也就是对一个已经是代理对象的对象,再去为它生成代理对象。

假设一开始生成了一个代理类类名为$Proxy0,在InterceptorChain#pluginAll方法中,会将这个代理类作为委托类继续生成一个新的代理类,第一个代理类会执行ExamplePluginA拦截逻辑,第二个代理类会执行ExamplePluginB的拦截逻辑。

从pluginAll方法中可以看到,位于拦截器链末尾的,也可以说是最后被创建的那个代理类,是最先被调用的,因为实际返回给客户端使用的,就是它。

假设第二个代理类类名为$Proxy1,那么看一下这种情况下方法的调用栈是啥样的

mybaits-plugin-complicate

四、总结

这里主要说一下mybatis为什么这样实现?

  • 为什么不采用过滤器链的实现方式?

    过滤器链的方式,在这里并不怎么适用,虽然也许可以,个人观点觉得,过滤器链更多的是用于过滤,它是对调用请求进行条件判断,是否满足某种条件进而是否具备某个继续执行的权限。它决定的是,调用是否可以继续进行下去。

    而拦截器,更多的是拦截调用请求,对拦截后的请求做一些额外的附加逻辑,代理其实就是这种方式,它是一种对原有逻辑的增强,不会改变最初调用的目的地,无论做了多少层的拦截处理,最终都会到达它的目的地(发生异常除外)

    如果用过滤器,需要多个过滤器链,并且每个类中都需要持有对其过滤器链的引用等等,用我浅薄的知识稍微想了下,并非不可,实而太麻烦了。最优选择还是动态代理。

  • 为什么要做封装?

    回想一下我们直接使用Jdk的动态代理,自己动手实现InvocationHandler,写完就没了,也就是说就做了一次增强。

    但是这里情况更加复杂,可能有多个类的多个方法需要被增强,以Executor为例,如果我们每个方法都要增强,并且每个方法的增强逻辑都不一样,而实际上,最终也只生成一个代理对象,那我们就要在一个InvocationHandler的invoke方法中,大量的if-else判断(这里也可以优化if-else),当前调用的是哪个方法,应该执行什么样的逻辑。这样在实现上是没问题的,只不过对一个框架来说,易用性也是强有力的吸引力、竞争力。如果这些不优雅的或者用户实现起来比较麻烦的事,框架都给封装好,简单易用,那么肯定会更加受欢迎,这肯定也会是一个好的框架

Codex CLI 手机号验证失败?5 种接码平台实测对比与绕过地区限制的 3 步操作 揭示 Codex CLI 手机号验证失败的真实原因在于上下文污染而非网络问题,分析其通过 ASN、Accept-Language 和 TLS SNI 三重加权风控的机制,并实测对比 5 种接码平台在 DNS 解析路径、ASN 干净度和复用间隔上的差异,提出剥离浏览器指纹、固化 TLS SNI、隔离 阅读详情

相关推荐

MS建模mmt

一、流程:1.定义好每个原子力场类型:Edit Sets(分组) 2.加H(一般是仅与Al-O八面体中的Al相连的O原子)、给H分组 3.“make P1”、校核化学式(正确与否) 4.扩成超晶胞(Na-mmt:4*1*1,Ca-mmt:4*2*1,illite:2*1*1,由化学式而定) 5.置换阳离子: mmt:模型中每 32 个 Si 4+有 1 个被 Al 3+ 取...

weixin_30721899的博客 2174

Mybatis之插件开发

关于mybatis插件开发,其实通俗一点就是mybatis拦截器 主要用于在sql执行前拦截sql进行相应的处理 常用地方: 1、公共字段统一赋值,mybatis-plus中的自动填充注解实现其实就是这个原理 2、mybatis分页,也是通过这种方式植入xml分页参数的 3、性能监控,对于SQL语句执行的性能监控,可以通过拦截Executor类的update, query等方法,用日志记录每个方法...

weixin_41387105的博客 1505

AnyGrasp实战指南:从环境配置到抓取检测与跟踪

本文详细介绍了AnyGrasp从环境配置到抓取检测与跟踪的实战指南。涵盖硬件要求、关键依赖安装避坑、抓取检测与跟踪的实战技巧,以及常见问题解决方案和性能优化建议,帮助开发者快速掌握这一高精度物体抓取检测与跟踪技术。

weixin_33712987的博客 274

java踩坑笔记——MyBatis中update返回结果

在实际项目过程中其实可以通过另一种方式解决,不再对update返回结果进行判断,如果修改失败,那么一般情况下是会有异常发生,所以对于返回结果的判断并不是必要的。很多猿在撸码时都会对update、delete、insert等返回结果进行判断,若返回数量大于0则继续后续步骤,这样可以一定程度上确保数据一致性。同样的数据在预生产环境流程可以继续向下,可是在生产环境却被阻断。debug发现预生产环境返回1,生产环境返回0,所以造成阻断。以上代码根据count判断,如果count>0则继续,否则通知用户修改失败。

qq_26839911的博客 2971

[亚信线上教学] AX58100: EtherCAT从站设备仿真功能设计教学

什么情况需要开启EtherCAT从站设备仿真功能呢? 一般来说, 当EtherCAT从站产品,不需要使用额外的微控制器介入,或使用不具备EtherCAT从站通讯协议栈的微控制器一同协作的情况下,就必须开启EtherCAT从站设备仿真功能,这样EtherCAT主站才能够正常设置从站设备的工作状态. 亚信AX58100 EtherCAT从站控制芯片的优点 AX58100 EtherCAT从站控制器, 集成2个百兆以太网Phis, 并支持一些额外的控制接口, 例如脉冲宽度调变, 增量, 霍尔编码器, .

allanchou1的专栏 7423

【Unity】【模型】【AI建模】如何将AI生成的GLB格式3D模型文件导入Unity

本文介绍了一个将AI工具自动生成的GLB格式3D模型文件转换成fbx模型文件导入Unity的步骤。

O青草O的博客 Unity和游戏制作知识分享 1357

mybatis 中update 返回值

mybatis中update函数返回值

HANHUABAO1122的博客 1万+

Open3D点云数据处理(六):点云、mesh可视化(Visualizer类)

本文介绍了Open3D中Visualizer类可视化几何对象的方法,给出了常用参数解释和代码示例。

孙悟空 3025

Mybatis Update操作返回值问题

Mybatis Update操作返回值问题在项目中有些时候我们需要根据更新是否成功,来判断下个操作我们需要如何处理,在获取update操作的返回值时遇到了一个问题,似乎 Mybatis 进行 update 操作得到的 int 返回值并不是影响的行数,这就导致了我们的判断条件失效。 后端的数据持久化使用的是 Mybatis ,在做高并发下账户增减余额的时候,打算使用乐观锁来解决这个问题。在获取upd...

z646721826的博客 3万+

SI案例分享--FPC(柔性电路板)信号仿真

设计高性能的柔性PCB时,由于采用了网格地的参考面构造,因此,需要按照特定的结构进行布局,才可以保证所需目标阻抗的稳定性,该结构的配置过程称为“Hatch Configuration”,合理的参数配置将有助于得到满意的设计效果。

一只豌豆象的博客 2827

【Python基础】01 如何安装Python及集成环境

本文详细介绍了Python 3.13开发环境的完整搭建流程,涵盖三大操作系统(Windows/macOS/Linux)的Python安装方法、PyCharm专业IDE的配置使用,以及pip包管理工具的应用技巧。内容包括:Python 3.13各系统安装指南、PyCharm社区版与专业版的安装配置、环境验证方法、pip的基本命令与镜像源优化、虚拟环境管理,以及常见问题的解决方案。通过本教程,读者可获得一个高效完备的Python开发环境,为后续编程学习打下坚实基础。

nmdbbzcl的博客 1419

mybatis源码分析(八):拦截器

拦截器 拦截器的作用就是在执行sql的过程中插入一些执行逻辑,比如记录当前执行的sql、分页等 使用 @Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocati

lxlneversettle的博客 688

串口通信协议

文章目录前言一、串口通信结构图二、电平三、串口通信协议 前言 本文记录的是平时常用的串口通信有关知识点 提示:以下是本篇文章正文内容,下面案例可供参考 一、串口通信结构图 1、RS232标准串口通讯结构图 2、USB转串口通讯结构图 3、原生的串口到串口 二、电平 串口通信的时候,有三种电平:TTL电平、RS232电平、USB电平 TTL电平是从MCU直接出来的电平 RS323是一种通讯标准,因为高电平+15V低电平–15V电位差30V容错空间大,抗干扰能力强,一般用于工业设备直接通信电平转换芯

weixin_43772611的博客 6850

mybatis 小于_阿里架构师万字总结:Mybatis插件实现原理,Mybatis就要这么用

欢迎关注专栏《Java架构筑基》——专注于Java技术的研究与分享!Java架构筑基Java架构筑基——专注于Java技术的研究与分享!后续文章将首发此专栏!欢迎各位Java工程师朋友投稿和关注mybatis中的插件,也就是拦截器interceptor,也挺有意思的。它的简单使用,就直接拿文档中的示例来简单说下一、使用使用方式很简单Copy然后如果是xml配置的话<plugins> ...

weixin_39554434的博客 72

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

mybatis update返回值_阿里架构师万字总结:Mybatis插件实现原理,Mybatis就要这么用

mybatis中的插件,也就是拦截器interceptor,也挺有意思的。它的简单使用,就直接拿文档中的示例来简单说下一、使用使用方式很简单Copy// 使用这个注解,表明这是一个拦截器 @Intercepts( // 方法签名 {@Signature( // 被拦截方法所在的类 type= Executor.class, // 被拦截方法名 method =...

weixin_39723655的博客 166

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

首发 阿里年薪100W架构师整理万字MyBatis实战笔记,精简易懂,开源免费下载

MyBatis作为国内经常使用的持久层框架,其内部代码的设计非常优秀。比如在开发过程中,有能力对框架进行深度的定制化开发,解决BUG也更加得心应手!另外学习开发者是如何设计高扩展性、低耦合性的代码,便于在自己的开发场景中应用。 而在跳槽的时候MyBatis更是面试必问的内容,那你对于MyBatis又掌握了多少呢?想学习MyBatisK但,市面上真正适合学习的MyBatis资料太少,有的书或资料虽然讲得比较深入,但是语言晦涩难懂,大多数人看完这些书基本都是从入门到放弃。学透MyBatis源码难道就真的就没有一

m0_70083198的博客 158

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等

今天就由阿里一线P8架构师揭秘,对他使用的技术进行了一个总结,这个PDF总结主要涉及到Spring、MyBatis源码以及Tomcat等,希望能够帮助到大家,对自己有一定提升。分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。最后,想提醒的一句,学习到的东西,都是自己的,如果你需要这些架构技术使用总结。添加图片注释,不超过 140 字(可选)

代码界的扛把子 1049

阿里为什么弃用hibernate ?看完Mybatis技术原理实战我终于明白

hibernate和mybatis是当前流行的ORM框架。hibernate对数据库结构提供了较为完整的封装。mybatis主要着力点在于java对象与SQL之间的映射关系。 MyBatis和hibernate孰优孰劣?一直都饱受争议,这不,前几天群里关于这个话题,又吵起来了。 众多过来人总结出来的经验就是:hibernate确实厉害,但MyBatis入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。..

文章中资料均可获取,有需要请添加yunduoa2019即可 2069

原理+实战都有了!阿里架构师带你深入浅出MyBatis技术

Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet结果集执行的内存分页,而非物理分页,可以在 sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。分页插件的基本原理是使用 Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写sql,根据dialect 方言,添加对应的物理分页语句和物理分页参数。这些场景在大量的编码中使用,具备较强的实用价值,这些内容都是通过实战得来的,供读者们参考。

m0_57042151的博客 304

mybatis批量夺标添加_深入原理,从实战出发,阿里架构师带你深入浅出MyBatis技术...

前言:先给大家分享一道京东金融的面试题:Mybatis 是如何进行分页的?分页插件的原理是什么?参考答案:Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet结果集执行的内存分页,而非物理分页,可以在 sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。分页插件的基本原理是使用 Mybatis提供的插件接口,实现自定义插件,在插件...

weixin_42432918的博客 96

不愧是阿里资深架构师,这份“Mybatis学习笔记”写得如此透彻明了

各行各业从事者也有不同等级划分,作为程序员你属于哪个层次呢?身为普通程序员想要进阶高级程序员,实际上,作为程序员,丰富自己的知识储备,提升自己的知识深度和广度是很有必要的,付出更多努力更是必然的。文中资料已整理打包存放网盘,有需要的朋友可以点击下方的名片自取!

m0_73311735的博客 161

阿里10年架构师:由Java基础架构+MySQL

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习已经将知识体系整理好(源码,笔记,PPT,学习视频)经将知识体系整理好(源码,笔记,PPT,学习视频)[外链图片转存中…(img-7tbJ9B7m-1710765935925)][外链图片转存中…(img-yOVNrST5-1710765935925)][外链图片转存中…(img-O20e0xLp-1710765935926)]本文已被。

2201_75604580的博客 1095

字节跳动架构师年薪,mybatis之插件机制(1)

Override@Override@Override复制代码2)由于我们要对 Executor 的查询进行拦截,所以在其上添加对应的拦截注解说明,当然这里是可以拦截多种接口的value = {复制代码3) 加一个Properties类型成员用来接收配置中设置的值,并在执行具体路基之前输出配置中对应的内容,当然你也可以直接写死输出hellovalue = {@Override@Override@Override复制代码。

2401_84408418的博客 874

阿里技术官十年经验,写出的Mybatis笔记,完整版免费下载

前言: Mybatis是一款优秀的持久层框架。其封装了JDBC操作, 免去了开发人员编写JDBC 代码以及设置参数和获取结果集的重复性工作。通过编写简单的 XML 或Java注解即可映射数据库CRUD操作。本文介绍的是阿里资深架构师十年经验整理,Mybatis顶级学习笔记,从原始的JDBC谈起,深入浅出讲解Mybatis实战技巧。 由于笔记内容偏多,篇幅受限,只能在文章中展示部分的章节内容和核心截图,如果你需要完整的PDF版本,可以点此处免费领取。 MyBatis入门:(附源码解析) 1.MyBatis

爱写代码的程序员 234

mybatis 日志_阿里资深架构师整理分享内部绝密MyBatis源码深度解析文档

前言MyBatis作为持久层框架,以其小巧轻便、SQL可配置、使用简单等特点深受广大Java开发者喜爱。然而大多数开发人员对MyBatis框架的理解仅局限于使用,并不理解框架底层的实现原理。作为一名开发人员,阅读开源框架的源码,可以学习源码中对设计模式及面向对象设计原则的应用,有助于提升自身编码能力。笔者在工作之余,深入研究了MyBatis框架的源码,本文将会从源码的角度分析MyBatis框架各个...

weixin_39615956的博客 107

阿里资深架构师整理分享内部绝密MyBatis源码深度解析文档

介绍MyBatis的核心组件,包括Configuration、SqlSession、Executor、MappedStatement等,包括这些组件的作用及 MyBatis执行SQL语句的核心流程。

公众号:该用户快成仙了 147
上一篇: 很少有人会告诉你的5个编程名言,安排!
下一篇: 队列是如何逐步进化成一个消息中间件的?
Java_Cappuccino
博客等级 码龄7年 17粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值