Mybatis在Spring中的使用(二)

文章概述

本文承接上文《Mybatis在Spring中的使用(一)》,主要介绍了mybatis的注解的使用方法

使用注解

把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定Sql语句。
同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名

在实际开发中,越简便越好,所以都是采用不写dao实现类的方式,不管使用XML还是注解配置,但mybatis支持自己写dao类

mybatis执行过程

  1. 根据配置文件的信息创建Connection对象,注册驱动,获取连接
  2. 获取预处理对象PreparedStatement,此时需要Sql语句conn.prepareStatement(sql)
  3. 执行查询.ResultSet resultSet = preparedStatement.executeQuery()
  4. 遍历结果用于封装
List<E> list = new ArrayList();
while(resultSet.next()){
    E element = (E)Class.forName(
        /*配置的全限定类名(com.xxx.IXXDao)*/)
        .newInstance();
    //进行封装,吧每个result的内容都添加到element
    //中去。
    /**
    *因为实体类属性和表中的列名是一致的
    *所以可以把表的列名看成是实体类的属性名称
    *就可以使用反射的方式来根据名称获取每个属性,并
    *把值赋进去
    */
    //把element放入到list中
    list.add(element);
}
  1. 返回list
    return list;

要想让上面的步骤执行,我们需要给方法提供两个信息

  • 连接信息
  • 映射信息
    它包含了两个部分
    • 执行的Sql语句
    • 封装结果的实体类全限定类名
      这两个信息组和起来定义成一个对象(Mapper)
      Key:com.xxx.IUserDao.findAll
      Value:Mapper对象,包含了Sql语句以及实体类的全限定类名

同样的,还需要一个可以根据dao接口的字节码创建dao的代理对象

public <T> getMapper(Class<T> daoInterfaceClass){
    /*
    *类加载器:使用和被代理对象是相同的类加载器
    代理对象要实现的接口:和被代理对象实现相同的接口
    如何代理:增强的方法,我们要自己提供
    此处是一个InvocationHandle接口,要写一个
    该接口的实现类
    在实现类中调用selectList,就是上面的1,2,3,4,5
    **/
    Proxy.newProxyInstance(类加载器,
    代理对象要实现的接口字节数组,如何代理)
}

自定义实现

步骤

  1. 首先通过类加载器读取全局的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--<!DOCTYPE configuration
        PUBLIC "-//mybatis.org/DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">-->
<!--mybatis主配置文件-->
<configuration>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置id为mysql的环境-->
        <environment id="mysql">
            <!--表示事物的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!--配置连接数据库的四个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="xie2481"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定映射配置文件的位置 映射配置文件指的是每个dao独立的配置文件
    如果是用注解来配置,应该使用class属性指定被注解的dao全限定类名-->
    <mappers>
        <mapper resource="mybatis/dao/IUserDao.xml"/>
        <!--mapper class="mybatis.dao.IUserDao"/-->
    </mappers>
</configuration>
package mybatis.io;

import java.io.InputStream;

/**
 * 使用类加载器读取配置文件的类
 * **/
public class Resources {
    /**
     * 根据传入的参数,获取一个字节输入流
     * */
    public static InputStream getResourceAsStream(String filePath){
        return Resources.class.getClassLoader().getResourceAsStream(filePath);
    }
}

  1. 创建SqlSessionFactory工厂,获取数据库连接SqlSession的Factory
package mybatis.sqlsession;

import mybatis.cfg.Configuration;
import mybatis.sqlsession.defaults.DefaultSqlSessionFactory;
import mybatis.utils.XMLConfigBuilder;

import java.io.InputStream;

/**
 * 用于创建一个SqlSessionFactoryBuilder对象
 来构造SqlSessionFactory
 * */
public class SqlSessionFactoryBuilder {
    /**
     * 根据参数的字节输入流来构建一个SqlSessionFactory工厂
     * */
    public SqlSessionFactory build(InputStream config){
        Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
        return new DefaultSqlSessionFactory(cfg);
    }
}

SqlSessionFactory是一个接口方法,需要自定义一个实现类

package mybatis.sqlsession;

public interface SqlSessionFactory {
    /**
     * 用于打一个新的SqlSession对象
    * */
    SqlSession openSession();
}
package mybatis.sqlsession.defaults;

import mybatis.cfg.Configuration;
import mybatis.sqlsession.SqlSession;
import mybatis.sqlsession.SqlSessionFactory;

/**
 * SqlSessionFactory实现类
 */
public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private Configuration cfg;

    public DefaultSqlSessionFactory(Configuration cfg){
        this.cfg = cfg;
    }

    /**
     * 用于创建一个新的操作数据库对象
     * @return
     */
    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(cfg);
    }
}
  1. 使用SqlSessionFactory生产一个SqlSession对象
package mybatis.sqlsession;
/**
 * 自定义mybatis中和数据库交互的核心类
 * 创建dao的代理对象
 * */
public interface SqlSession {
    /**
     * 根据参数创建一个代理对象,参数是dao接口字节码
     * */
    <T> T getMapper(Class<T> daoInterfaceClass);

    /**
     * 释放资源
     * */
    void close();
}
package mybatis.sqlsession.defaults;

import mybatis.cfg.Configuration;
import mybatis.sqlsession.SqlSession;
import mybatis.sqlsession.proxy.MapperProxy;
import mybatis.utils.DataSourceUtil;

import java.lang.reflect.Proxy;
import java.sql.Connection;

/**
 * SqlSession接口的实现类
 */
public class DefaultSqlSession implements SqlSession{

    private Configuration cfg;
    private Connection connection;
    public DefaultSqlSession(Configuration cfg){
        this.cfg = cfg;
        connection = DataSourceUtil.getConnection(cfg);
    }

    /**
     * 用于创建代理对象
     * @param daoInterfaceClass
     * @param <T>
     * @return
     */
    @Override
    public <T> T getMapper(Class<T> daoInterfaceClass) {
        return (T)Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
                new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
    }

    /**
     * 用于释放资源
     */
    @Override
    public void close() {
        if(connection != null){
            try {
                connection.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}
  1. 使用SqlSession对dao接口的对象创建代理增强
    代理对象的实现类如下
package mybatis.sqlsession.proxy;

import mybatis.cfg.Mapper;
import mybatis.utils.Executor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Map;

public class MapperProxy implements InvocationHandler {

    //map的key是全限定类名+方法名
    private Map<String, Mapper> mappers;
    private Connection conn;

    public MapperProxy(Map<String,Mapper> mappers,Connection conn){
        this.mappers = mappers;
        this.conn = conn;
    }
    /**
     * 用于对方法进行增强,我们的增强就是调用selectList方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1获取方法名
        String methodName = method.getName();
        //2获取方法所在类的名称
        String className = method.getDeclaringClass().getName();
        //3组合key
        String key = className + "." + methodName;
        //4获取mappers中的mapper对象
        Mapper mapper = mappers.get(key);
        if(mapper == null){
            throw  new IllegalArgumentException("传入的参数有误");
        }
        //6调用工具类,执行查询所有

        return new Executor().selectList(mapper,conn);
    }
}

完整流程图

以下图片截自网络,侵删

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值