MyBatis

== 1、#{}和${}的区别:==

(1)#{}是参数占位符,MyBatis会将SQL中的#{}替换为 ?,实际参数值替换

在SQL运行前会使用PreparedStatement对象的参数设置方法,执行sql语句,将按序给参数占位符替换后的?

安全性高效率高能避免sql注入

例:

select id,name,email,age from student where id=#{studentId}select id,name,email,age from student where id=?

#{user.name} 利用反射从参数对象中获取 user对象 的属性值 name

(2)${}是变量占位符,静态文本替换、字符串替换

使用$包含的字符串替换所在的位置,使用Statement对象把sql语句和${}内存连接起来

安全性低效率低有sql注入风险

一般可用于替换表名、列名,能确定数据安全的可以使用

例:

select id,name,email,age from student where id=${studentId}select id,name,email,age from student where id=1005

${driver} 静态替换为 com.mysql.jdbc.Driver

 

==2、xml映射文件中的常见标签==

select、insert、update、delete、trim、where、set、foreach、if、choose、when、otherwise、bind、sql、include、resultMap、parameterMap、selectKey

==3、动态sql==

原理:使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,来完成动态sql的功能。

动态sql可以在xml映射文件中,以标签形式编写动态sql,实现逻辑判断和动态拼接sql的功能

if

如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回,反之若传入了“title”,那么就会把模糊查找“title”内容的BLOG结果返回

加入另一个条件同理

<select id="findActiveBlogLike" resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
       <if test="title != null">
          AND title like #{title}
       </if>
       <if test="author != null and author.name != null">
          AND author_name like #{author.name}
       </if>
   </select>

choose 、when、otherwise 选择其中的条件之一,没有条件达成就返回所有

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
   <choose>
       <when test="title != null">
          AND title like #{title}
       </when>
       <when test="author != null and author.name != null">
          AND author_name like #{author.name}
       </when>
       <otherwise>
          AND featured = 1
       </otherwise>
   </choose>
</select>

trim、where、set

if中有值的情况下,才会执行where,where会自动去除AND\OR

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
   <where>
       <if test="state != null">
          state = #{state}
       </if>
       <if test="title != null">
          AND title like #{title}
       </if>
       <if test="author != null and author.name != null">
          AND author_name like #{author.name}
       </if>
   </where>
</select>

set一般用于动态更新 会自动消去无关的“,”

<update id="updateAuthorIfNecessary">
  update Author
   <set>
       <if test="username != null">username=#{username},</if>
       <if test="password != null">password=#{password},</if>
       <if test="email != null">email=#{email},</if>
       <if test="bio != null">bio=#{bio}</if>
   </set>
  where id=#{id}
</update>

sql

foreach 允许指定一个集合 或 指定字符串(可有分隔符)

<sql id="studentSql">
      select id,name,age,email from student
</sql>
<select id="selectStudentForeachOne" resultType="com.qifengle.domain.Student">
       <include refid="studentSql"/> where id in
       <foreach collection="list" item="myI" open="(" close=")" separator="," >
          #{myI}
       </foreach>
</select>

==4、主要的类的介绍==

(1)Resources 负责读取mybatis配置文件

InputStream in = Resources.getResourceAsStream(”mybatis.xml“);

(2)SqlSessionFactoryBuilder 通过build方法创建SqlSessionFactory对象 创建后的不需要了,相当于局部变量

SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = sfb.build(in);

(3)SqlSessionFactory 核心类 是一个接口 创建后运行期间一直存在 全局变量 可以创建多个SqlSession

接口实现类:DefaultSqlSessionFactory

SqlSessionFactory作用: 获取SqlSession对象

SqlSession sqlSession = factory.openSession();

openSession()方法:无参方法获取非自动提交事务的SqlSession对象

openSession(boolean)方法:true获取自动提交事务的SqlSession对象 不用写commit提交事务、false要写commit来提交事务

(4)SqlSession 接口 定义了操作数据库的方法(select()、insert()、commit()等) 每个SqlSession可以有多个Mapper业务

该接口实现类:DefaultSqlSession :实现操作数据库的方法

 

SqlSession对象不是线程安全的,需要在方法内部使用,

在执行sql语句前,使用openSession()获取SqlSession对象

在执行完sql语句后,需要关闭它,执行sqlSession.close(),这样能保证它的使用是线程安全的

==5、通常一个XML映射文件对应一个Dao接口(Mapper接口),工作原理是什么?==

Mapper接口工作原理:JDK动态代理+key-value

JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成proxy代理对象,该代理对象会拦截接口方法,执行MappedStatement所代表的sql,执行sql后返回结果。

接口权限名+方法名 作为 key值,可以唯一定位一个MappedStatement

(1)Mapper接口,接口权限名 == XML映射文件中的namespace

(2)接口的方法名 == XML映射文件中MappedStatement的id值

(3)接口方法内参数 == 传递给sql的参数

例:com.heyuliang.mapper.StudentMapper.findStudentById

Key:namespace(com.heyuliang.mapper.StudentMapperid)+id(findStudentById)

Value:对应的唯一的MappedStatement对象

mybatis中每个<select><insert><update><delete> 标签都会解析为一个个MappedStatement对象

==6、分页==

分页插件的原理:使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截sql,然后重新sql,根据dialect方言,添加对应的物理分页语句和物理分页参数

MyBatis仅可以编写针对这 4 种接口的插件:ParameterHandlerResultSetHandlerStatementHandlerExecutor

分页实现过程:JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能。

实现拦截的方法:InvocationHandlerinvoke()` 方法

自定义插件:实现 Interceptor 接口,重写intercept()方法,执行要拦截的接口及方法

例:select * from student 拦截后重写

select t.* from(select * from student) t limit 0 ,10

(1)PageHelper 物理分页(数据量大时推荐使用) MyBatis通用的分页插件 支持多种数据库

调用startPage,会通过PageInterceptor对后边的第一个sql语句进行拦截,并拼接上limit语句

(2)RowBounds 内存分页(数据量小适合使用)

使用RowBounds对象进行分页,是针对ResultSet结果集执行的内存分页。先将所有结果查询出来,然后通过计算offset和limit,返回部分结果,操作在内存中进行。

(3)SQL内部limit 物理分页

直接在SQL语句中直接书写带物理分页的参数(limit)来完成物理分页功能

==7一对一一对多 关联查询==

(1)一对一 一个sql查询关联对象

(2)使用嵌套查询,使用join查询

去重原理:<resultMap> 标签中的<id>标签,指定了唯一确定记录的id列,MyBatis根据<id>列来完成去重复的功能,之一著对象有去重。

==8、**延迟加载**==

(1)、仅支持association关联对象(一对一)和collection关联集合对象(一对多)的延迟加载

(2)配置文件中配置: lazyLoadingEnabled=true|false

(3)原理:使用CGLIB动态代理插件目标对象的代理对象。

例:调用 a.getB().getName() ,拦截器 invoke() 方法发现 a.getB() 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。

==9、不同XML映射文件id是否可重复==

获取MappedStatement的方式是用Map集合获取Map<String,MappedStatement>,key-value的形式,可以是namespace+id。

不同映射文件,若配置了namespace,id可以重复,若没有配置namespace,则id不能重复。

==10、MyBatis的执行器==

三种基本的Executor执行器

(1)SimpleExecutor执行器

每执行一次update\select,就开启一个Statement对象,用完后就关闭

(2)ReusuExecutor执行器:

每执行update\select,先根据key查找Map中是否存在Statement对象,若不存在就创建并使用,若存在就使用,用完不关闭,放置回Map。可重复使用Statement对象

(3)BatchExecutro执行器

完成批处理 JDBC批处理不支持select

执行update,缓存了多个Statement对象,将所有的sql添加到批处理中(addBatch()),等待统一执行(executeBatch())。

(4)指定Executor执行器:配置文件中指定的ExecutorType类型参数

==11、MyBatis映射文件和内部数据结构的映射关系==

(1)xml配置信息被封装到Configuration内部中。

(2)<parameterMap> 标签会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。

(3)<resultMap> 标签会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。

(4) <select>、<insert>、<update>、<delete> 标签均会被解析为 MappedStatement 对象

(5)标签内的 sql 会被解析为 BoundSql 对象。

==12、MyBatis缓存==

(1)查询缓存特性,提高查询效率 MyBatis有两级缓存

(2)默认开启:一级缓存(SqlSession级别的缓存)

(3)开启二级缓存配置:setting

(4)选择缓存:select标签

(5)flushCache属性:增删改默认flushCache=true Sql执行后同时清空一二级缓存

(6)sqlSession.clearCache():只用来清除一级缓存

= 1、一级缓存

(1)SqlSession级别缓存,本地缓存

(2)作用域:默认sqlSession

(3)清空清空:Session flush \ close 时 所有Cache将清空

(4)不能被关闭,可配置作用域

(5)工作机制:同一次会话期间,只要查询过的数据都保存在当前SqlSession的一个Map中。

(6)缓存失效情况:不同SqlSession对应不同的一级缓存、同一个SqlSession下查询不同的条件、同一SqlSession下两次查询中有增删改操作、有进行过手动清空缓存的操作

=2、二级缓存

(1)全局作用域缓存

(2)默认不开启,需要手动配置

(3)需要pojo实现Serializable接口

(4)开启的配置:<setting name = "cacheEnable" vlaue = "true"/>

=3、自定义缓存

(1)实现Cache接口

(2)EhCache框架的使用


posted @ 2022-04-14 17:39  与长安故里  阅读(72)  评论(0编辑  收藏  举报