【愚公系列】2023年04月 Java教学课程 116-Mybatis(动态代理和动态SQL)


一.动态代理

1.1 代理开发方式介绍

Mybatis的动态代理是指在运行时动态生成DAO接口的实现类,这个实现类不需要手动编写,而是由Mybatis框架自动生成。

Mybatis的动态代理主要是使用JDK动态代理和CGLIB动态代理两种方式实现的。在接口有实现类的情况下,Mybatis会优先使用JDK动态代理,否则使用CGLIB动态代理。

在使用Mybatis时,我们只需要编写DAO接口,并在映射文件中配置SQL语句,Mybatis框架就会自动为我们生成实现类,并将SQL语句和DAO接口方法进行绑定,使得我们可以通过接口调用SQL语句。

动态代理的优点是可以减少代码量,提升开发效率。同时,Mybatis的动态代理还可以实现一些高级功能,比如分页查询、多表关联查询等。

Mapper 接口开发需要遵循以下规范:

1) Mapper.xml文件中的namespace与mapper接口的全限定名相同

2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同

4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

总结:

接口开发的方式: 程序员只需定义接口,就可以对数据库进行操作,那么具体的对象怎么创建?

1.程序员负责定义接口

2.在操作数据库,mybatis框架根据接口,通过动态代理的方式生成代理对象,负责数据库的crud操作

1.2.编写StudentMapper接口

在这里插入图片描述

1.3 测试代理方式

1、配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
    mapper:核心根标签
    namespace属性:名称空间
-->
<mapper namespace="com.itheima.mapper.StudentMapper">

    <sql id="select" >SELECT * FROM student</sql>

    <!--
        select:查询功能的标签
        id属性:唯一标识
        resultType属性:指定结果映射对象类型
        parameterType属性:指定参数映射对象类型
    -->
    <select id="selectAll" resultType="student">
        <include refid="select"/>
    </select>

    <select id="selectById" resultType="student" parameterType="int">
        <include refid="select"/> WHERE id = #{
    
    id}
    </select>

    <insert id="insert" parameterType="student">
        INSERT INTO student VALUES (#{
    
    id},#{
    
    name},#{
    
    age})
    </insert>

    <update id="update" parameterType="student">
        UPDATE student SET name = #{
    
    name},age = #{
    
    age} WHERE id = #{
    
    id}
    </update>

    <delete id="delete" parameterType="int">
        DELETE FROM student WHERE id = #{
    
    id}
    </delete>

    <select id="selectCondition" resultType="student" parameterType="student">
        <include refid="select"/>
        <where>
            <if test="id != null">
                id = #{
    
    id}
            </if>
            <if test="name != null">
                AND name = #{
    
    name}
            </if>
            <if test="age != null">
                AND age = #{
    
    age}
            </if>
        </where>
    </select>

    <select id="selectByIds" resultType="student" parameterType="list">
        <include refid="select"/>
        <where>
            <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
</mapper>

在这里插入图片描述

2、测试动态代理

public class Test01 {
    
    
    @Test
    public void selectByIds() throws Exception{
    
    
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //4.获取StudentMapper接口的实现类对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);

        //5.调用实现类的方法,接收结果
        List<Student> list = mapper.selectByIds(ids);

        //6.处理结果
        for (Student student : list) {
    
    
            System.out.println(student);
        }

        //7.释放资源
        sqlSession.close();
        is.close();
    }

    @Test
    public void selectCondition() throws Exception{
    
    
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //4.获取StudentMapper接口的实现类对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        Student stu = new Student();
        stu.setId(2);
        stu.setName("李四");
        //stu.setAge(24);

        //5.调用实现类的方法,接收结果
        List<Student> list = mapper.selectCondition(stu);

        //6.处理结果
        for (Student student : list) {
    
    
            System.out.println(student);
        }

        //7.释放资源
        sqlSession.close();
        is.close();
    }
}

1.4 源码分析

  • 分析动态代理对象如何生成的?

    通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。

  • 分析方法是如何执行的?

    动态代理实现类对象在执行方法的时候最终调用了 mapperMethod.execute() 方法,这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查。

二、总结

接口代理方式可以让我们只编写接口即可,而实现类对象由 MyBatis 生成。

实现规则 :

  1. 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同。
  2. 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同。
  3. 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同。
  4. 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同。 
  5. 获取动态代理对象 SqlSession 功能类中的 getMapper() 方法。

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/129830444