Mybatis的介绍与使用

本文探讨了主流的Spring-SpringMVC-Mybatis(SSM)框架与SSH框架的变迁,重点讲解了Mybatis的使用流程,包括配置、映射文件、参数处理、Mapper代理模式以及SQL执行顺序,同时涵盖了表连接查询和缓存机制的详解。
摘要由CSDN通过智能技术生成

1.当前的主流框架

SSM框架: 现在主流 Spring SpringMVC Mybatis 轻量级框架

SSH框架: SSM框架之前主流的: Spring + Struts2 + Hibernate 轻量级框架 不依赖环境

EJB框架: 重量级框架: SSH框架之前主流(SUN) 依赖开发环境, 开发环境不一样, 代码也不一样

2.使用mybatis的主要流程

1.各个部分的联系

2.Mybatis执行流程图:

3.mybatis-config.xml核心配置文件的基本框架

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--开发环境-->
    <environments default="mysql">
        <environment id="mysql">
            <!--事务管理器: JDBC: 使用jdbc管理事务, 需要手动提交事务-->
            <transactionManager type="JDBC"/>
            <!--dataSource数据源的类型: POOLED 连接池   UNPOOLED: 不带连接池 -->
            <dataSource type="POOLED">
                <!--数据库四大参数-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/0311db?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=GMT%2b8"/>
                <property name="username" value="root"/>
                <property name="password" value="admin123"/>
            </dataSource>
        </environment>
    </environments>


    <!--加载sql映射文件-->
    <mappers>
        <!--相对路径
          判断路径是否写错, 按住ctrl不放,
        -->
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

4.Mybatis细节(#{}${} 面试高频 )

1.使用#{} 接收列名时,它只是作为一个常量值插入

2.使用${}接收列名,作为sql语句进行插入

5.面试细节(selectOne 与selectList 的区别)

都是集合,只不过selectOne是经过判断,如果大于一条记录会抛出一异常

6.InputStream,SqlSessionFactoryBuilder,SqlSessionFactory,SqlSession 的scope作用域

InputStream, SqlSessionFactoryBuilder:

一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域

方法的局部变量

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次

作为静态属性

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域

方法的局部变量

7.mybatis的Mapper代理模式(方法和步骤)

1.被代理接口: 包含方法签名

2.编写对应的Sql映射文件: 满足Mapper代理实现的要求

1.sql映射文件的namespace必须是对应Dao接口的全限定名(包.接口名)

2.sql映射文件的Statement的id必须是对应方法的方法名

3.service类得到Mapper接口代理对象

1.service层方法
public class UserServiceImpl implements UserService {
  UserMapper userMapper= MybatisUtil.getMapper(UserMapper.class);
    @Override
    public boolean saveUser(User user) {
        //调用UserDao
        try {
            return userMapper.add(user);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return false;
    }
}

2.使用一个自己整合的工具类得到mapper代理接口对象
package com.fs.util;


import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author suke
 * @version 1.0
 * @title MybatisUtil
 * @description Mybatis工具类
 * @create 2024/4/15 17:47
 */
public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    //tl 被多个线程共享,  SqlSession不共享,每个线程都有自己的SqlSession
    private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();


    static{
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession openSqlSession(){
        SqlSession sqlSession = tl.get();
        if(sqlSession == null){
            sqlSession =  sqlSessionFactory.openSession();
            tl.set(sqlSession);
        }
        return sqlSession;
    }

    public static void close(){
        SqlSession sqlSession = tl.get();
        if(sqlSession != null){
            sqlSession.commit();
            sqlSession.close();
            tl.remove();//防止内存泄漏
        }
    }


    //定义泛型方法 <T>: 定义泛型变量    T: 使用泛型变量
    // MybatisUtil.getMapper(UserMapper.class);
    public static <T> T getMapper(Class<T> clazz){
        SqlSession sqlSession = tl.get();
        if(sqlSession == null){
            sqlSession = openSqlSession();
        }
        return sqlSession.getMapper(clazz);
    }



}

8.sql语句需要传入多个参数时(三种方式)

9.动态sql的使用方法

1.提供了动态sql标签:

if: if条件

  • where: where关键字

  • foreach: 循环标签

  • set: set关键字

  • sql: sql片段, 重复sql的重用

1.<if>

<if test="条件(属性名)">
    sql片段
</if>

 例子

如果传入的是对象类型时

 要进行非空判断进行优化

2.<where>

  1. where关键字
  2. 去掉sql语句中第一个and或者or

把条件包裹在where标签内部

 <select id="selectByCondition" parameterType="UserCondition" resultType="User">
        select * from tb_user
        <where>
            <!--如果用户传递这个条件, sql语句拼接这个条件
              判断userCondition是否为null,如果为null, 没有条件
            -->
            <if test="userCondition != null">
                <if test="userCondition.user != null ">
                    <!--username: String  非空判断有两种情况: null, ""
                         只有字符串才判断 "", 其他类型一定不能判断""
                    -->
                    <if test="userCondition.user.username != null and userCondition.user.username!=''  ">
                        and username like #{userCondition.user.username}
                    </if>
                    <if test="userCondition.user.sex != null and userCondition.user.sex!=''  ">
                        and sex = #{userCondition.user.sex}
                    </if>
                </if>

                <if test="userCondition.startDate != null">
                    and brithday >= #{userCondition.startDate}
                </if>
                <if test="userCondition.endDate != null">
                    and brithday &lt;= #{userCondition.endDate}
                </if>
            </if>
        </where>
    </select>

3.<set >

  1. set关键字

  2. 去掉最后一个逗号

4.<foreach>

 

 <select id="selectByIds" resultType="User">
        select * from  tb_user where
        <!--循环产生sql片段
          collection:  集合/数组,   list集合: list   数组: array
          item:循环变量
          separator: sql片段的连接符:
          open: sql片段前部分
          close: sql片段后部分
          循环生成sql:
           " id = 20 or id = 21 or id =22 "
           "id in(20,21,22)"

           sql片段 = open + (循环片 + separator +循环片 )  + close
        -->
        <foreach collection="array" item="i" separator="or" open=" " close=" ">
            id = #{i}
        </foreach>
    </select>

5.<sql>

代替重复的sql代码

10.表连接查询(三种表的连接查询)

1.一对一

外键列可以加在任何一方, 但是这个外键列必须添加一个唯一约束

类的设计

2.一对多

类的设计 

3.多对多 

多对多关联关系: 使用中间表维护表的关系, 中间表由两个外键组成, 这两个外键组合一个主键

11.缓存机制

缓存

缓存作用: 1. 提高查询效率(减少SQL执行)

2.减轻数据库服务器的压力

Mybatis的缓存

Mybatis有两级缓存

  • 一级缓存: 默认开启, 基于SqlSession的

    同一个SqlSession执行相同的sql语句, 后面的执行都将从SqlSession缓存获取数据, 当SqlSession关闭之后, 该SqlSession中一级缓存数据删除

    1. 不同的SqlSession,无法共享一级缓存, 同一个SqlSession,才共享一级缓存

    2. 一旦SqlSession执行增删改操作, 先清空缓存, 为了保存缓存与数据库的数据一致性

  • 二级缓存

基于Mapper的二级缓存, 不同sqlSession执行相同mapper(namespace)中相同sql语句, 并且传递参数参数, 也就是执行相同的sql语句, 那就会先从二级缓存查询数据,如果二级缓存没有数据,才到数据库查询, 如果二级缓存有数据, 返回缓存中的数据

Mybatis的全局二级缓存开启: 表示Mybatis允许使用二级缓存

<settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

cacheEnabled默认值: true

开启Mapper的二级缓存,没有开启

  1. 在mapper映射文件中使用 <cache/>

表示该Mapper下的所有的查询都进行二级缓存

<cache/>有type属性, 指定Cache的实现类, 默认:SerializedCache(序列化的缓存实现)

面试题: 自定义mybatis二级缓存, 怎么实现:

  1. 编写一个类实现Cache接口

  2. 在Mapper配置文件中, <cache type="你的Cache实现类全限定名"/>

  1. 对Mapper下查询的返回值类型,实现可序列化接口:

    SerializedCache: 要求数据进行序列化操作

面试题:

查询执行顺序:

如果二级缓存开启, 首先走的是二级缓存, 如果二级缓存(tcm)有, 直接返回, 如果没有, 走一级缓存(localCache) ,如果一级缓存有, 直接返回, 如果一级缓存没有: 从数据库查询

单独关闭某个Statement的二级缓存:

二级缓存中,如果执行增删改, 清空二级缓存.

  • 56
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值