Mybatis

:src/main/java和src/main/resources是同一个目录
注意:如果是取简单数量类型的参数,括号中的参数名称必须为value
例:

   <select id="findUserByUsername" parameterType="java.lang.String"
                 resultType="com.kkb.mybatis.po.User">
      select * from user where username like '%${value}%'
   </select>

如果参数类型是Collection的,括号中的参数名称必须是Collection;如果是List的,名称必须是list,如果是array的,名称必须是array
源码:
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap map = new StrictMap<>();
map.put(“collection”, object);
if (object instanceof List) {
map.put(“list”, object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap map = new StrictMap<>();
map.put(“array”, object);
return map;
}
return object;
}
#{}和${}区别
区别1:
#{}:相当于JDBC SQL语句中的占位符? (PreparedStatement)
${}:相当于JDBC SQL语句中的连接符合 + (Statement)
区别2:
#{}:进行输入映射的时候,会对参数进行类型解析(如果是String类型,那么SQL语句会自动加上’’)
${}:进行输入映射的时候,将参数原样输出到SQL语句中
区别3:
#{}:如果进行简单类型(String、Date、8种基本类型的包装类)的输入映射时,#{}中参数名称可以任意
: 如 果 进 行 简 单 类 型 ( S t r i n g 、 D a t e 、 8 种 基 本 类 型 的 包 装 类 ) 的 输 入 映 射 时 , {}:如果进行简单类型(String、Date、8种基本类型的包装类)的输入映射时, StringDate8{}中参数名称必须是value
区别4:
${} :存在SQL注入问题 ,使用OR 1=1 关键字将查询条件忽略

Mybatis开发方式
1.原始dao开发方式
@Before
publicvoid init() throws Exception {
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream(“SqlMapConfig.xml”);
sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
}
@Test
publicvoid testFindUserById() {
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
User user = userDao.findUserById(22);
System.out.println(user);
}
2.mapper代理开发方式(JDK的代理方式)
2.1 代理
动态代理分为两种方式:
基于JDK的动态代理–针对有接口的类进行动态代理 ************
基于CGLIB的动态代理–通过子类继承父类的方式去进行代理。
2.2 XML方式
只需要开发Mapper接口(dao接口)和Mapper约束文件,不需要编写实现类
Mapper接口开发需要遵循以下规范:
1、 Mapper接口的类路径与Mapper.xml文件中的namespace相同。
2、 Mapper接口方法名称和Mapper.xml中定义的每个statement的id相同。
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
4、 Mapper接口方法的返回值类型和mapper.xml中定义的每个sql的resultType的类型相同。
3. 注解方式
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
代替了 标签和标签
@Result 中 属性介绍:column 数据库的列名,Property 需要装配的属性名,one 需要使用的@One 注解(@Result(one=@One)())),many需要使用的@Many 注解(@Result(many=@many)()))
@Results:可以与@Result 一起使用,封装多个结果集
代替的是标签,该注解中可以使用单个@Result 注解,也可以使用@Result 集合,@Results({@Result(),@Result()})或@Results(@Result())
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射

生命周期(作用范围)
1. sqlsession:方法级别
2. sqlsessionFactory:全局范围(应用级别)
3. sqlsessionFactoryBuilder:方法级别

全局配置文件
typeAlias标签
别名的作用:就是为了简化映射文件中parameterType和ResultType中的POJO类型名称编写
1.默认支持别名
2.自定义别名
在SqlMapConfig.xml中进行如下配置:

<typeAliases>
       <!-- 单个别名定义 -->
       <typeAlias alias="user" type="com.kkb.mybatis.po.User"/>
       <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
       <package name="com.kkb.mybatis.po"/>
</typeAliases>
 mappers标签
      1.<mapper resource=""/>
             使用相对于类路径的资源
             如:<mapper resource="sqlmap/User.xml" />
      2.<mapper url="">
          使用绝对路径加载资源
          如:<mapper url="file://d:/sqlmap/User.xml" />
      3.<mapper class=""/>
          使用mapper接口类路径,加载映射文件
          如:<mapper class="com.kkb.mybatis.mapper.UserMapper"/>
       注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中,且mapper映射文件namespace和mapper接口类路径名称相同
      4.<package name=""/>
          注册指定包下的所有mapper接口,来加载映射文件
          如:<package name="com.kkb.mybatis.mapper"/>
          注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中

源码
在这里插入图片描述

  • XMLxxxBuilder是用来解析XML配置文件的,不同类型XMLxxxBuilder用来解析MyBatis配置文件的不同部位。
    1、 XMLConfigBuilder用来解析MyBatis的全局配置文件
    2、 XMLMapperBuilder用来解析MyBatis中的映射文件
    3、 XMLStatementBuilder用来解析映射文件中的statement语句。
    4、 MapperBuilderAssistant用来辅助解析映射文件并生成MappedStatement对象

映射文件
输入类型parameterType

  • 包装对象:pojo类中包含pojo。
  • #{}:是通过反射获取数据的
    ${}:是通过OGNL表达式会随着对象的嵌套而相应的发生层级变化
    例:
<select id="findUserList" parameterType="queryVo" resultType="user">
              SELECT * FROM user where username like '%${user.username}%'
 </select>

输出类型

  1. resultType
    resultType属性可以映射的java类型有:简单类型、POJO类型、Map类型
    使用resultType进行输出映射时,要求sql语句中查询的列名和要映射的pojo的属性名一致
  2. resultMap
    如果sql查询列名和pojo的属性名不一致,可以通过resultMap将列名和属性名作一个对应关系,最终将查询结果映射到指定的pojo对象中。
    注意:resultType底层也是通过resultMap完成映射的
    例:
    将以下sql的查询结果进行映射:
     SELECT id id_,username username_,birthday birthday_ FROM user
     <!-- 定义resultMap:将查询的列名和映射的pojo的属性名做一个对应关系 -->
     <!--
          type:指定查询结果要映射的pojo的类型
          id:指定resultMap的唯一标示,此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个
      -->
     <resultMap type="user" id="userListResultMap">
               <!--
                   id标签:映射查询结果的唯一列(主键列)
                   column:查询sql的列名
                   property:映射结果的属性名
               -->
               <id column="id_" property="id"/>
               <!-- result标签:映射查询结果的普通列 -->
               <result column="username_" property="username"/>
               <result column="birthday_" property="birthday"/>
     </resultMap>
 <!-- resultMap入门 -->
  <select id="findUserListResultMap" resultMap="userListResultMap">
      SELECT id id_,username username_,birthday birthday_ FROM user
  </select>

使用resultMap进行结果映射时,具体是使用resultMap的子标签association(一对一)和collection(一对多)完成关联查询的映射,将关联查询信息映射到pojo对象中
resultMap完成结果映射的方式是以[主信息]为主对象,[从信息]映射为集合或者对象,然后封装到主对象中

MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟
MyBatis根据对关联对象查询的select语句的执行时机,分为三种类型:直接加载、侵入式加载与深度延迟加载
例:
System.out.println(订单信息) – 将用户信息直接加载 --直接加载
System.out.println(订单信息.getID) – 查询数据库 --侵入式延迟加载
System.out.println(订单信息.用户信息.getID) – 查询数据库 --深度延迟加载
1.直接加载
通过对全局参数:lazyLoadingEnabled进行设置,默认就是false。

<settings>
   <!-- 延迟加载总开关 -->
   <setting name="lazyLoadingEnabled" value="false"/>
</settings>

2.侵入式延迟加载

<settings>
   <!-- 延迟加载总开关 -->
   <setting name="lazyLoadingEnabled" value="true"/>
   <!-- 侵入式延迟加载开关 -->
   <setting name="aggressiveLazyLoading" value="true"/>
</settings>

3.深度延迟加载

<settings>
    <!-- 延迟加载总开关 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 侵入式延迟加载开关 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

N+1问题

  • 深度延迟加载的使用会提升性能。
  • 如果延迟加载的表数据太多,此时会产生N+1问题,主信息加载一次算1次,而从信息是会根据主信息传递过来的条件,去查询从表多次。

动态SQL
1.if标签

<select id="findUserList" parameterType="queryVo" resultType="user">
              SELECT * FROM user where 1=1
              <if test="user != null">
                     <if test="user.username != null and user.username != ''">
                            AND username like '%${user.username}%'
                     </if>
              </if>
</select>

2.where标签
上边的sql中的1=1,虽然可以保证sql语句的完整性:但是存在性能问题。Mybatis提供where标签解决该问题。
代码修改如下:

   <select id="findUserList" parameterType="queryVo" resultType="user">
          SELECT * FROM user
          <!-- where标签会处理它后面的第一个and -->
          <where>
                 <if test="user != null">
                        <if test="user.username != null and user.username != ''">
                               AND username like '%${user.username}%'
                        </if>
                 </if>
          </where>
   </select>

3.sql片段
在映射文件中可使用sql标签将重复的sql提取出来,然后使用include标签引用即可,最终达到sql重用的目的,具体实现如下:

  • 原映射文件中的代码:
<select id="findUserList" parameterType="queryVo" resultType="user">
              SELECT * FROM user
              <!-- where标签会处理它后面的第一个and -->
              <where>
                     <if test="user != null">
                            <if test="user.username != null and user.username != ''">
                                   AND username like '%${user.username}%'
                            </if>
                     </if>                    
              </where>
       </select>
  • 将where条件抽取出来:
<sql id="query_user_where">
              <if test="user != null">
                     <if test="user.username != null and user.username != ''">
                            AND username like '%${user.username}%'
                     </if>
              </if>
</sql>
  • 使用include引用:
   <!-- 使用包装类型查询用户 使用ognl从对象中取属性值,如果是包装对象可以使用.操作符来取内容部的属性 -->
   <select id="findUserList" parameterType="queryVo" resultType="user">
          SELECT * FROM user
          <!-- where标签会处理它后面的第一个and -->
          <where>
                 <include refid="query_user_where"></include>
          </where>
 
   </select>

注意:
1、如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:<include refid="namespace.sql片段”/>
2.foreach

 <if test="ids != null and ids.size() > 0">
                 <!-- collection:指定输入的集合参数的参数名称 -->
                 <!-- item:声明集合参数中的元素变量名 -->
                 <!-- open:集合遍历时,需要拼接到遍历sql语句的前面 -->
                 <!-- close:集合遍历时,需要拼接到遍历sql语句的后面 -->
                 <!-- separator:集合遍历时,需要拼接到遍历sql语句之间的分隔符号 -->
                 <foreach collection="ids" item="id" open=" AND id IN ( "
                        close=" ) " separator=",">
                        #{id}
                 </foreach>
          </if>

注意:如果parameterType不是POJO类型,而是List或者Array的话,那么foreach语句中,collection属性值需要固定写死为list或者array

缓存介绍

  • Mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
  • Mybatis的查询缓存总共有两级,我们称之为一级缓存和二级缓存,如图:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值