MyBatis--动态代理实现dao接口

1、CRUD代码分析

  • 规律: 参数结构相似, 参数1指定对应的statement, 参数2 实际需要参数值
    在这里插入图片描述

2、思路分析

问题一、是否可以通过动态代理,代理UserDAO接口,然后动态生成内部的增删改查代码呢?

  • 应该是可以的,因为代码有很多相似之处,都是调用SqlSession的增删改查方法,然后 调用 对应的 statement ,传递对应的Sql参数。
  • 模式虽然类似,但是我们有新的问题:

问题二、想要让Mybatis帮我们动态生成DAO代码,有以下问题需要解决?

  • A:如何确定要调用SqlSession的哪个方法?
    • 每一个DAO中的方法,最终一定对应Mapper.xml中的一个statement,而每个statement中定义的Sql语句,就可以知道应该是增、删、改、查中的哪一个。
    • 所以要确定应该调用SqlSession的哪个方法,就要先确定DAO的方法对应mapper.xml中的哪个statement
  • B:如何确定要调用哪个statement?
    • 要确定statement,就必须通过两个参数:mapper.xml文件的namespace + 这个statement的ID
    • 而我们知道,这两个值都是用户自定义的,可以是任意值。如果是这样,我们是无法确定的!
    • 但是,我们刚才定义namespace和ID并不是任意的:
namespace恰好就叫UserMapper,与UserDAO接口相关
statement的id恰好与每一个方法的名称一致。
其实呢,在Mybatis中,也是采用类似的约定来做的,mybatis对于Mapper.xml文件的定义有以下约定:
  • 约定namespace必须与DAO接口的全名称一致
  • 约定statement的ID必须和接口中的方法名称一致
  • 这样以来,Mybatis的底层,只要拿到我们定义的接口,以及接口的方法名称,必然能确定到对应的statement,从而知道我们应该调用哪个SqlSession方法,知道返回值类型是什么,知道参数类型是什么,从而帮我们动态生成DAO的实现代码!
    在这里插入图片描述

如何通知mybatis名称空间?

  • 解决: 指定名称空间dao接口的全路径, 包名 + 类名

如何通知mybatis那条语句? sql语句的id

  • 解决:dao接口的方法名 和 mapper文件的id保持一致

3、mybatis动态代理实现dao接口

3.1、规则

  • 要想动态代理实现dao接口的方法, 关键在于找到对应的statement. 如果想快速找到对应的statment, 就需要遵守如下约定:
    • 每一个dao接口 都有一个对应的 XxxMapper.xml映射文件(必须)
      -mapper.xml文件的namespace必须是接口的全名称(必须)
    • mapper.xml文件的每个statement的id必须是 dao接口的方法名(必须)
    • statement中定义的resultType必须和方法定义的返回值类型一致(必须)
    • 在MyBatis中, 一般dao接口命名规则为 XxxMapper.java, 不是 XxxxDao.java(虽然这不是必须的)
  • 如果遵守以上约定, myBatis很对就可以实现动态代理

3.2、编写Mapper接口(代替dao接口)

.在这里插入图片描述

package cn.hanjiaxiaozhi.mapper;import cn.hanjiaxiaozhi.pojo.User;import java.util.List;public interface UserMapper {
    /**
     * 根据编号 查询用户
     */
    public User queryUserById(Long id);/**
     * 查询所有用户
     */
    public List<User> queryUserList();/**
     * 添加用户
     */
    public void insertUser(User user);/**
     * 修改用户
     */
    public void updateUser(User user);/**
     * 根据编号 删除客户
     */
    public void deleteById(Long id);
}

3.3、修改 UserMapper.xml文件

  • xml文件的namespace必须是 mapper接口的全路径
  • 每个statement的id 必须 mapper接口的方法名保持一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
    定义所有用到的sql语句 和 映射关系
    namespace : 当前这个配置文件的唯一标识, 自定义, 但是不能和其他配置文件namespace重复
-->
<mapper namespace="cn.hanjiaxiaozhi.mapper.UserMapper">
    <!--
        定义一条sql语句, 其实就是一个 statement
            select 代表是查询语句, 与其类似的还有 insert, update, delete等
            id : 这条sql语句的唯一标识,自定义,但是不能和其他sql语句重复
            parameterType:  sql语句需要的参数类型, 需要写 类的全路径
            resultType: sql语句返回的结果类型
    -->

    <select id="queryUserById" parameterType="java.lang.Long" resultType="cn.hanjiaxiaozhi.pojo.User">
        <!--这里写具体的sql语句, #{}是占位符, 编译时会被替换成?, 然后注入真实参数-->
        select *,user_name as userName from tb_user where id=#{id}
    </select>

    <!--查询所有用户-->
    <select id="queryUserList" resultType="cn.hanjiaxiaozhi.pojo.User">
        select *,user_name as userName from tb_user
    </select>

    <!--添加用户-->
    <insert id="insertUser" parameterType="cn.hanjiaxiaozhi.pojo.User">
        insert into tb_user
        (
            id,
            user_name,
            password,
            name,
            age,
            sex,
            birthday,
            created,
            updated
         )
        values (
            null,
            #{userName},
            #{password},
            #{name},
            #{age},
            #{sex},
            #{birthday},
            now(),
            now()
        )
    </insert>

    <!--修改用户-->
    <update id="updateUser" parameterType="cn.hanjiaxiaozhi.pojo.User">
        update tb_user
            set
                user_name = #{userName},
                password = #{password},
                name = #{name},
                age = #{age},
                sex = #{sex},
                birthday = #{birthday},
                updated = now()
        where id = #{id}
    </update>

    <!--删除用户-->
    <delete id="deleteById" parameterType="java.lang.Long">
        delete from tb_user
        where id = #{id}
    </delete>
</mapper>

3.4 测试
.在这里插入图片描述

package cn.hanjiaxiaozhi.mapper;

import cn.hanjiaxiaozhi.pojo.User;
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 org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

import static org.junit.Assert.*;

public class UserMapperTest {
    private UserMapper userMapper;

    @Before
    public void setUp() throws Exception {
        String resource = "mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void queryUserById() throws Exception {
        User user = userMapper.queryUserById(1L);
        System.out.println(user);
    }

    @Test
    public void queryUserList() throws Exception {
        List<User> userList = userMapper.queryUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

3.5、总结

  • MyBatis动态代理生成dao的步骤:
    • 编写数据管理的接口 XxxMapper.java
    • 编写接口对应的配置文件 XxxxMapper.xml
      • namespace必须 和 dao接口的全路径保持一致
      • statement的id必须 和 dao接口的方法名保持一致
      • statement的resultType类型 必须 和方法返回值类型保持一致
    • 通过 sqlSession.getMapper(类的字节码对象) 获取代理之后的Mapper实现类对象
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值