入门案例参见:
设计分析
main函数里都在干什么?
// 1.读取配置文件
// 这是相对类的路径,读取配置文件时通常使用两个方法:
// a. 类加载器 b.使用ServletContext对象的getRealPath()
InputStream in = Resources.getResourceAsStream("mybatis.xml");
// 2.创建SqlSessionFactory工厂,构建者模式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3.使用工厂生成SqlSession对象,工厂模式
SqlSession session = factory.openSession();
// 4.使用SqlSession创建Dao接口的代理,代理模式
IUserDao userDao = session.getMapper(IUserDao.class);
// 5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user:users){
System.out.println(user);
}
// 6.释放资源
session.close();
in.close();
自定义ORM框架的思路:
- 根据配置文件的信息创建Connection对象
注册驱动,获取连接 - 获取预处理对象PreparedStatement
此时需要SQL语句
conn.prepareStatement(sql) - 执行查询
ResultSet set = psm.executeQuery() - 遍历结果集用于封装
Listlist = new ArrayList();
while(resultSet.next()){
E element = xxxx;(通过反射)
//进行封装
list.add(element);
} - 返回list
return list;

实现
仓库地址:
http://git.codetool.top/RhettPeng/mybatis_design/src/master
使用类加载器读取配置文件
public class Resources {
/**
* 根据传入的参数,获取一个字节输入流
*/
public static InputStream getResourceAsStream(String filePath){
return Resources.class.getClassLoader().getResourceAsStream(filePath);
}
}
使用输入流构建工厂
public class SqlSessionFactoryBuilder {
/**
* 根据参数的字节输入流来构建一个SqlSessionFactory工厂
* @param config
* @return
*/
public SqlSessionFactory build(InputStream config){
//XMLConfigBuilder用于解析xml配置文件并生成Configuration对象
Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
return new DefaultSqlSessionFactory(cfg);
}
}
Configuration:
public class Configuration {
private String driver;
private String url;
private String username;
private String password;
private Map<String,Mapper> mappers = new HashMap<>();
//getter & setter...
}
Configuration里面包含了所有读出来的mapper映射,key为全限定类名.方法名
,value为Mapper对象,Mapper类:
/**
* 用于封装执行的SQL语句和结果类型的全限定类名
*/
public class Mapper {
private String queryString;//SQL
private String resultType;//返回类型
//getter & setter...
}
工厂接口:
public interface SqlSessionFactory {
/**
* 用于创建一个SqlSession对象
* @return
*/
SqlSession openSession();
}
使用工厂获取session对象
/**
* 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);
}
}
SqlSession接口:
/**
* 自定义Mybatis和数据库交互的核心类
* 它里面可以创建dao接口的代理对象
*/
public interface SqlSession {
/**
* 根据参数创建一个代理对象
* @param daoInterfaceClass dao的字节码
* @param <T>
* @return
*/
<T> T getMapper(Class<T> daoInterfaceClass);
/**
* 释放资源
*/
void close();
}
使用Session获取一个mapper对象
这里使用了动态代理,默认SqlSession实现:
public class DefaultSqlSession implements SqlSession {
private Configuration cfg;
private Connection connection;
public DefaultSqlSession(Configuration cfg){
this.cfg = cfg;
this.connection = DataSourceUtil.getConnection(cfg);
}
/**
* 用于创建代理对象
* @param daoInterfaceClass dao的字节码
* @param <T>
* @return
*/
//通过传过来的接口找到Mapper映射中对应的Mapper对象,然后使用InvocationHandler构建动态代理对象
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
T mapper = (T)Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(), new Class[]{daoInterfaceClass}, new MapperProxy(cfg.getMappers(), connection));
return mapper;
}
/**
* 用于释放资源
*/
@Override
public void close() {
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
MapperProxy:
public class MapperProxy implements InvocationHandler {
//key:全限定类名+方法名
private Map<String, Mapper> mappers;
private Connection conn;
public MapperProxy(Map 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);
//5. 判断是否有mapper
if(mapper==null){
throw new IllegalArgumentException("传入的参数有误");
}
//6. 调用工具类执行查询所有
return new Executor().selectList(mapper,conn);
}
}
用户定义的Mapper:
public interface IUserDao {
/**
* 查询所有操作
*/
List<User> findAll();
}
总结

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e6%a8%a1%e4%bb%bfmybatis%e5%85%a5%e9%97%a8%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0%e4%b8%80%e4%b8%aaorm%e6%a1%86%e6%9e%b6/