文章概述
本文承接上文《Mybatis在Spring中的使用(一)》,主要介绍了mybatis的注解的使用方法
使用注解
把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定Sql语句。
同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名
在实际开发中,越简便越好,所以都是采用不写dao实现类的方式,不管使用XML还是注解配置,但mybatis支持自己写dao类
mybatis执行过程
- 根据配置文件的信息创建Connection对象,注册驱动,获取连接
- 获取预处理对象PreparedStatement,此时需要Sql语句conn.prepareStatement(sql)
- 执行查询.ResultSet resultSet = preparedStatement.executeQuery()
- 遍历结果用于封装
List<E> list = new ArrayList();
while(resultSet.next()){
E element = (E)Class.forName(
/*配置的全限定类名(com.xxx.IXXDao)*/)
.newInstance();
//进行封装,吧每个result的内容都添加到element
//中去。
/**
*因为实体类属性和表中的列名是一致的
*所以可以把表的列名看成是实体类的属性名称
*就可以使用反射的方式来根据名称获取每个属性,并
*把值赋进去
*/
//把element放入到list中
list.add(element);
}
- 返回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(类加载器,
代理对象要实现的接口字节数组,如何代理)
}
自定义实现
步骤
- 首先通过类加载器读取全局的配置文件
<?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);
}
}
- 创建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);
}
}
- 使用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();
}
}
}
}
- 使用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);
}
}
完整流程图
以下图片截自网络,侵删