mybatis动态代理
文章目录
- 动态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动态代理相关推荐
- Mybatis动态代理模式实现CRUD
项目实现的功能 查询所有用户信息 通过Id查询用户信息 添加用户(回显主键) 修改用户信息 删除用户信息 通过用户名字模糊查询 一.引入依赖和工程结构 <?xml version="1 ...
- mysql动态代理_超全MyBatis动态代理详解(绝对干货)
前言 假如有人问你这么几个问题,看能不能答上来 Mybatis Mapper 接口没有实现类,怎么实现的动态代理 JDK 动态代理为什么不能对类进行代理(充话费送的问题) 抽象类可不可以进行 JDK ...
- 超全MyBatis动态代理详解!(绝对干货)
我的新课<C2C 电商系统微服务架构120天实战训练营>在公众号儒猿技术窝上线了,感兴趣的同学,可以长按扫描下方二维码了解课程详情: 课程大纲请参见文末 前言 假如有人问你这么几个问题,看 ...
- MyBatis动态代理原理
1. MyBatis核心组件 在详细探究MyBatis中动态代理机制之前,先来补充一下基础知识,认识一下MyBatis的核心组件. SqlSessionFactoryBuilder(构造器): 它可以 ...
- Mybatis动态代理和非动态代理的理解
Mybatis动态代理的好处 传统分层模式,我们在处理业务的时候需要些 dao 层,然后再 写 dao层的实现类 具体处理业务在 dao 层的实现类中进行处理, 而 mybatis 在配置 实体类的 ...
- 【Java18】Mybatis:jdbc解耦,动态代理,日志
文章目录 1.介绍:Mybatis是对数据库操作,创建maven管理的java工程就可以 2.第一个程序:三个.xml文件 2.1 pom.xml 2.2 log4j.properties 2.3 m ...
- Mybatis搞两下(sqlsession,动态代理)
本文主要介绍和,其中动态代理实操了源码,我觉得值得一看,能加深你对Mybatis底层文件的映射,代理类进行的CRUD的操作,即使他本身也是通过SqlSession来执行增删改查的操作. SqlSess ...
- c++map的使用_mybatis源码 | mybatis插件及动态代理的使用
学习背景 最近公司在做一些数据库安全方面的事情,如数据库中不能存手机号明文,不能存身份证号明文, 但是项目已经进行了好几个月了, 这时候在应用层面去改显然不太现实, 所以就有了Mybatis的自定义插 ...
- 初看Mybatis 源码 (二) Java动态代理类
先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...
最新文章
- 《OpenCV3编程入门》学习笔记1 邂逅OpenCV
- 做人应该知道的十个道理
- 关于MYsql 多字段排序
- JasperReport学习笔记2-创建简单的报表例子
- Mac 下安装mysqldb 问题:一条命令解决mysql_config not found
- ASP.NET Core 单元测试:如何Mock Url.Page()
- windows下使用net-snmp实现agent扩展(四)
- gdal读写图像分块处理
- mysqlbinlog: unknown variable 'default-character-s
- habernet备份mysql_harbor 安装
- mysql字符串查询_mysql字符串查询常用命令
- 买笔记本电脑主要看什么?
- c语言小球消砖块的游戏,求大神帮忙看看这个弹弹球消砖块的游戏代码,为什么speed只能15...
- firefox html5 pop,数组的push、unshift、pop、shift方法实现
- windows10系统怎么管理 右键-新建菜单
- 解决hive 中 beeline无法连接问题
- 残差网络解决什么问题详解残差网络
- 【leetcode刷题笔记】动态规划
- java道路上需要坚挺
- 华为P40或将搭载鸿蒙,厉害了任正菲的华为:P40或将搭载鸿蒙系统很快就要上市了...
热门文章
- 根据IP地址,子网掩码计算主机所在网络的网络地址和广播地址
- Swift 4 无限滚动轮播图(UICollectionView实现)
- 12.10 Nginx访问日志 12.11 Nginx日志切割 12.12 静态文件不记录日志和过期时间
- centos 6.5网卡固定IP重启出错
- ubuntu 安装 Sublime Text 2
- 根据坐标获取地图经纬度
- mysql 多列索引的生效规则
- Azure Redis 系列之 Azure Redis部署
- sdn和nfv的区别—Vecloud微云
- Ubuntu16.04能识别U盘,但无法识别光盘