文章目录

  • 动态SQL
    • if关键字
    • where 标签
    • where和if联合使用
    • set标签
    • trim标签
    • foreach标签
  • 动态代理
    • JDK自带动态代理
    • CGLib代理
      • 演示
  • MyBatis中的动态代理

动态SQL

采用OGNL表达式来进行SQL的淘汰不需要的元素。根据不同的添加进行动态的SQL的组装和拼接

if关键字

if标签:包含test表达式 必填,通过ognl表达式进行判断,true和false,
如果为真,会执行if中的SQL
如果为假,则不执行if中的SQL

where 标签

where标签作用:如果where标签包含了具有返回值时,就会插入一个where,如果where后面的字符串以and 和or开头的,则将他剔除

where和if联合使用

where表达式一般和if表达式一块使用,如果一个条件都不满足,则不拼接where到SQL中,如果有一个或者多个if表达式成立,where会直接拼接在SQL上,并且紧随where的表达式的and或者or会被忽略

<select id="selectClass" resultType="org.example.pojo.Class">select * from<where><if test="c_id!=null">and c_id=#{c_id}</if><if test="c_name!=c_name">and c_name=#{c_name}</if></where>

如果传入c_id则SQL语句为: select * from wherec_id=#{c_id}
两个都传入则SQL语句为:select * from c_id=#{c_id}

set标签

set标签的作用,如果set标签中的元素有返回值,就插入一个set,如果set后的字符串以逗号为结尾,则将最后的逗号剔除
set标签和if表达式一块使用,如果有条件满足时,会直接拼接一个set到SQL上,并将最后一个SQL的逗号去掉

<update id="updateStudent" parameterType="student" >update student<set><if test="Sname != null ">Sname  = #{Sname} ,</if><if test="Sage != null ">Sage  = #{Sage} ,</if></set>where SID = #{SID}</update>

trim标签

trim标签使用来去除SQL语句中多余的and关键字、逗号,或者给SQL拼接的where、set或者values等前后缀,可以选择性的进行插入、更显,或者添加查询操作
*prefix:前缀      
prefixoverride:去掉第一个and或者是or
suffix:后缀  
suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

<select id="selectStudentByDIY" parameterType="student" resultType="student">select * from Student<trim prefix="where" prefixOverrides="and"><if test="SID != null and SID != 0">and SID = #{SID}</if><if test="Sname != null ">and Sname  = #{Sname}</if></trim></select><update id="updateStudent" parameterType="student" >update student<trim prefix="set" suffixOverrides=","><if test="Sname != null ">Sname  = #{Sname} ,</if><if test="Sage != null ">Sage  = #{Sage} ,</if></trim>where SID = #{SID}</update>

foreach标签

批量处理
如:
insert table_name (id,name,age) values((1,1,1),(2,2,2))
select * from Student where SID in(1,2,3,4,5);

foreach标签实现批量数据处理,遍历集合对象
各属性解释

collection:必填,指定输入参数类型(列表:list  数组:array  hashmap:map)
item:起名字,给定集合中单个元素的名称
open:开始的字符串
close:结束的字符串
separator:数据之间的分隔符
index:索引的属性名,当类型为数组时是当前的索引值
 <select id="selectStudentByIds" resultType="student">select * from student where SID in<foreach collection="list" item="id"  open="(" close=")" separator="," index="">#{id}</foreach></select>

动态代理

代理模式是设计模式之一

委托类(RealSubject):真正实现功能或者提供真实服务
代理类(Proxy):并不提供真正实现服务,而是通过调用委托类的对象的相关方法提供特定服务,可以在该服务基础上提供一些其他的服务
subject:代理类和委托类共有的接口或者服务,提供了代理类和委托类共有方法
Client需要的服务是是通过代理类来获取的,而真正的服务是有委托类提供的

JDK自带动态代理

接口:

/*** 代理类和委托类共有的接口*/
public interface Iuser {void eate();
}

委托类:

/*** 委托类:具体实现接口中方法*/
public class User implements Iuser{@Overridepublic void eate() {System.out.println("User实现了eate方法");}
}

代理辅助类:

/*** 代理辅助类* 要实现动态代理,则需要给定一个实现类invocationHandler接口的实现类* 该类中需要持有IUser实现类的引用*/
public class UserProxy implements InvocationHandler {private Iuser user;public UserProxy(Iuser user){this.user=user;}/*** 实现InvocationHandler接口* 重写invoke方法* @param proxy :产生的代理对象* @param method:调用的方法* @param args :表示方法的参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理类自定义业务逻辑1");//调用委托类的方法method.invoke(user,args);System.out.println("代理类自定义业务逻辑2");return null;}

产生代理类的形式:

 public static void main(String[] args) {/*** ClassLoader loader,指定代理辅助类的加载器* Class<?>[] interfaces,当前被代理的接口* InvocationHandler h :代理辅助类*///产生的代理类Iuser user = (Iuser) Proxy.newProxyInstance(UserProxy.class.getClassLoader(), new Class[]{Iuser.class}, new UserProxy(new User()));user.eate();}

运行结果:

通过分析:动态打理的对象的产生通过Proxy.newProxyInstance()调用产生了代理对象
代理对象调用eate方法,通过打印结果可知,其调用了invocationHandler辅助类的invoke方法,该方法下来调用委托类User的eate实现

CGLib代理

JDK自带的动态代理使用比较简单,缺点也是明显的,需要目标对象实现一个或多个接口
当代理没有接口的类,此时Proxy和InvocationHandler机制就不能使用了,此时就需要使用cglib

cglib采用字节码技术,通过对字节码为一个类创建子类,并在子类中采用方法拦截的技术,拦截所有父类方法的调用,顺势织入横切技术

AOP技术的实现是使用到了JDK自带的动态代理和CGLib动态代理的

演示

引入依赖:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.2</version></dependency>

委托类:

public class CCGlibSuper {public void doing(){System.out.println("委托类");}
}

辅助类:

/*** 产生CGlib代理对象的辅助类* 实现MethodInterceptor* 该接口中的intercept方法需要实现*/
public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public <T> T getProxy(Class<T> tClass){//设置父类enhancer.setSuperclass(tClass);enhancer.setCallback(this);//通过字节码技术创建子类实例return (T)enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("代理类使用前");Object o1 = methodProxy.invokeSuper(o, objects);System.out.println("代理类使用后");return o1;}public static void main(String[] args) {CGLibProxy cgLibProxy = new CGLibProxy();CCGlibSuper proxy = cgLibProxy.getProxy(CCGlibSuper.class);proxy.doing();}
}

MyBatis中的动态代理

MyBatis中使用的是 JDK自带动态代理模式
添加接口信息如下

configuration.addMapper(StudentMapper.class);//添加mapper

addMapper方法实现:
Configuration类:

  public <T> void addMapper(Class<T> type) {mapperRegistry.addMapper(type);}

mapper实际上被添加到了mapperRegistry中
MapperRegistry类:

  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();public <T> void addMapper(Class<T> type) {if (type.isInterface()) { //只添加接口if (hasMapper(type)) {//不能重复添加throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<T>(type));MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}

mybatis在执行configuration.addMapper(StudentMapper.class),最终将接口信息放到HashMap中,名称为knownMappers,knownMappers是MapperRegistry类的私有属性,是一个HashMap,key为当前class对象,value为一个MapperProxyFactory类型的实例

继续看getMapper的代码跟踪

//通过动态代理机制(反射)产生了一个代理类(重点:动态代理模式,源码实现)StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

getMapper实现类通过debug测试确定为DefaultSQLSession类
DefaultSQLSession类:

  @Overridepublic <T> T getMapper(Class<T> type) {return configuration.<T>getMapper(type, this);}

该代码直接调用Configuration类中的getMapper方法
Configuration类:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}

通过代码是通过Proxy.newProxyInstance产生了一个StudentMapper接口的代理对象,mybatis为了完成mapper接口的实现运用了代理模式

mybatis动态代理相关推荐

  1. Mybatis动态代理模式实现CRUD

    项目实现的功能 查询所有用户信息 通过Id查询用户信息 添加用户(回显主键) 修改用户信息 删除用户信息 通过用户名字模糊查询 一.引入依赖和工程结构 <?xml version="1 ...

  2. mysql动态代理_超全MyBatis动态代理详解(绝对干货)

    前言 假如有人问你这么几个问题,看能不能答上来 Mybatis Mapper 接口没有实现类,怎么实现的动态代理 JDK 动态代理为什么不能对类进行代理(充话费送的问题) 抽象类可不可以进行 JDK ...

  3. 超全MyBatis动态代理详解!(绝对干货)

    我的新课<C2C 电商系统微服务架构120天实战训练营>在公众号儒猿技术窝上线了,感兴趣的同学,可以长按扫描下方二维码了解课程详情: 课程大纲请参见文末 前言 假如有人问你这么几个问题,看 ...

  4. MyBatis动态代理原理

    1. MyBatis核心组件 在详细探究MyBatis中动态代理机制之前,先来补充一下基础知识,认识一下MyBatis的核心组件. SqlSessionFactoryBuilder(构造器): 它可以 ...

  5. Mybatis动态代理和非动态代理的理解

    Mybatis动态代理的好处 传统分层模式,我们在处理业务的时候需要些 dao 层,然后再 写 dao层的实现类 具体处理业务在 dao 层的实现类中进行处理, 而 mybatis 在配置 实体类的  ...

  6. 【Java18】Mybatis:jdbc解耦,动态代理,日志

    文章目录 1.介绍:Mybatis是对数据库操作,创建maven管理的java工程就可以 2.第一个程序:三个.xml文件 2.1 pom.xml 2.2 log4j.properties 2.3 m ...

  7. Mybatis搞两下(sqlsession,动态代理)

    本文主要介绍和,其中动态代理实操了源码,我觉得值得一看,能加深你对Mybatis底层文件的映射,代理类进行的CRUD的操作,即使他本身也是通过SqlSession来执行增删改查的操作. SqlSess ...

  8. c++map的使用_mybatis源码 | mybatis插件及动态代理的使用

    学习背景 最近公司在做一些数据库安全方面的事情,如数据库中不能存手机号明文,不能存身份证号明文, 但是项目已经进行了好几个月了, 这时候在应用层面去改显然不太现实, 所以就有了Mybatis的自定义插 ...

  9. 初看Mybatis 源码 (二) Java动态代理类

    先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...

最新文章

  1. 《OpenCV3编程入门》学习笔记1 邂逅OpenCV
  2. 做人应该知道的十个道理
  3. 关于MYsql 多字段排序
  4. JasperReport学习笔记2-创建简单的报表例子
  5. Mac 下安装mysqldb 问题:一条命令解决mysql_config not found
  6. ASP.NET Core 单元测试:如何Mock Url.Page()
  7. windows下使用net-snmp实现agent扩展(四)
  8. gdal读写图像分块处理
  9. mysqlbinlog: unknown variable 'default-character-s
  10. habernet备份mysql_harbor 安装
  11. mysql字符串查询_mysql字符串查询常用命令
  12. 买笔记本电脑主要看什么?
  13. c语言小球消砖块的游戏,求大神帮忙看看这个弹弹球消砖块的游戏代码,为什么speed只能15...
  14. firefox html5 pop,数组的push、unshift、pop、shift方法实现
  15. windows10系统怎么管理 右键-新建菜单
  16. 解决hive 中 beeline无法连接问题
  17. 残差网络解决什么问题详解残差网络
  18. 【leetcode刷题笔记】动态规划
  19. java道路上需要坚挺
  20. 华为P40或将搭载鸿蒙,厉害了任正菲的华为:P40或将搭载鸿蒙系统很快就要上市了...

热门文章

  1. 根据IP地址,子网掩码计算主机所在网络的网络地址和广播地址
  2. Swift 4 无限滚动轮播图(UICollectionView实现)
  3. 12.10 Nginx访问日志 12.11 Nginx日志切割 12.12 静态文件不记录日志和过期时间
  4. centos 6.5网卡固定IP重启出错
  5. ubuntu 安装 Sublime Text 2
  6. 根据坐标获取地图经纬度
  7. mysql 多列索引的生效规则
  8. Azure Redis 系列之 Azure Redis部署
  9. sdn和nfv的区别—Vecloud微云
  10. Ubuntu16.04能识别U盘,但无法识别光盘