ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java-22 深入浅出 MyBatis - 手写ORM框架3 手写SqlSession、Executor 工作 [打印本页]

作者: 刘俊凯    时间: 2024-12-23 15:54
标题: Java-22 深入浅出 MyBatis - 手写ORM框架3 手写SqlSession、Executor 工作
点一下关注吧!!!非常感谢!!持续更新!!!

大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html


目前已经更新到了:


框架实现

上节已经实现了部分内容 下面我们继承

SqlSession 相干

SqlSessionFactoryBuilder

  1. public class SqlSessionFactoryBuilder {
  2.     private Configuration configuration;
  3.     public SqlSessionFactoryBuilder() {
  4.         configuration = new Configuration();
  5.     }
  6.     public SqlSessionFactory build(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException {
  7.         XMLConfigerBuilder xmlConfigerBuilder = new XMLConfigerBuilder(configuration);
  8.         Configuration conf = xmlConfigerBuilder.parseConfiguration(inputStream);
  9.         return new DefaultSqlSessionFactory(conf);
  10.     }
  11. }
复制代码
SqlSessionFactory

  1. public interface SqlSessionFactory {
  2.     SqlSession openSession();
  3. }
复制代码
SqlSession

  1. public interface SqlSession {
  2.     <E> List<E> selectList(String statementId, Object ...params) throws Exception;
  3.     <T> T selectOne(String statementId, Object ...params) throws Exception;
  4.     void close() throws Exception;
  5. }
复制代码
DefaultSqlSession

  1. @AllArgsConstructor
  2. public class DefaultSqlSession implements SqlSession {
  3.     private Configuration configuration;
  4.     private Executor simpleExecutor = new SimpleExecutor();
  5.     public DefaultSqlSession(Configuration configuration) {
  6.         this.configuration = configuration;
  7.     }
  8.     @Override
  9.     public <E> List<E> selectList(String statementId, Object... params) throws Exception {
  10.         MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
  11.         // System.out.println("DefaultSqlSession => selectList => + " + "statementId: " + statementId + ", mappedStatement: " + mappedStatement);
  12.         return simpleExecutor.query(configuration, mappedStatement, params);
  13.     }
  14.     @Override
  15.     public <T> T selectOne(String statementId, Object... params) throws Exception {
  16.         List<Object> objects = selectList(statementId, params);
  17.         if (objects.size() == 1) {
  18.             return (T) objects.get(0);
  19.         }
  20.         throw new RuntimeException("DefaultSqlSession selectOne 返回结果不唯一: " + statementId);
  21.     }
  22.     @Override
  23.     public void close() throws Exception {
  24.         simpleExecutor.close();
  25.     }
  26.     @Override
  27.     public <T> T getMapper(Class<?> mapperClass) {
  28.         Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
  29.             @Override
  30.             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  31.                 String methodName = method.getName();
  32.                 if (method.getDeclaringClass() == Object.class) {
  33.                     return method.invoke(this, args);
  34.                 }
  35.                 String className = method.getDeclaringClass().getName();
  36.                 String statementId = className + "." + methodName;
  37.                 Type genericReturnType = method.getGenericReturnType();
  38.                 if(genericReturnType instanceof ParameterizedType){
  39.                     List<Object> objects = selectList(statementId, args);
  40.                     return objects;
  41.                 }
  42.                 return selectOne(statementId,args);
  43.             }
  44.         });
  45.         return (T) proxyInstance;
  46.     }
  47. }
复制代码

类定义与注解

AllArgsConstructor:
用于生成包罗所有字段的构造方法,简化代码。
表示可以用所有字段直接构造一个 DefaultSqlSession 对象。
DefaultSqlSession:
实现了 SqlSession 接口,作为 MyBatis 的核心会话管理类。
包罗设置 (Configuration) 和执行器 (Executor) 的实例。
属性


工作原理总结

查询流程:

核心组件:

异常处置惩罚:

构造方法

DefaultSqlSession(Configuration configuration):

Executor 相干

Executor

  1. public interface Executor {
  2.     <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception;
  3.     void close() throws Exception;
  4. }
复制代码

DefaultExecutor

  1. public class SimpleExecutor implements Executor {
  2.     private Connection connection;
  3.     @Override
  4.     public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception {
  5.         connection = configuration.getDataSource().getConnection();
  6.         String sql = mappedStatement.getSql();
  7.         BoundSql boundSql = getBoundSql(sql);
  8.         PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
  9.         String parameterType = mappedStatement.getParameterType();
  10.         Class<?> parameterTypeClass = getClassType(parameterType);
  11.         List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
  12.         int n = 0;
  13.         for (ParameterMapping pm : parameterMappingList) {
  14.             String content = pm.getName();
  15.             Field declaredField = parameterTypeClass.getDeclaredField(content);
  16.             declaredField.setAccessible(true);
  17.             Object object = declaredField.get(params[0]);
  18.             preparedStatement.setObject(n + 1, object);
  19.         }
  20.         // 执行sql
  21.         ResultSet resultSet = preparedStatement.executeQuery();
  22.         String resultType = mappedStatement.getResultType();
  23.         Class<?> resultTypeClass = getClassType(resultType);
  24.         List<Object> objects = new ArrayList<>();
  25.         // 封装返回结果集
  26.         while (resultSet.next()) {
  27.             Object o = resultTypeClass.newInstance();
  28.             // 元数据
  29.             ResultSetMetaData metaData = resultSet.getMetaData();
  30.             for (int i = 1; i <= metaData.getColumnCount(); i ++) {
  31.                 // 字段名
  32.                 String columnName = metaData.getColumnName(i);
  33.                 // 字段的值
  34.                 Object value = resultSet.getObject(columnName);
  35.                 // 反射 根据数据库和实体 完成
  36.                 PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
  37.                 Method writeMethod = propertyDescriptor.getWriteMethod();
  38.                 writeMethod.invoke(o, resultTypeClass.getDeclaredField(columnName).getType().cast(value));
  39.             }
  40.             objects.add(o);
  41.         }
  42.         return (List<E>) objects;
  43.     }
  44.     private BoundSql getBoundSql(String sql) {
  45.         // 标记处理类 配置标记解析器来完成对占位符的解析处理工作
  46.         ParameterMappingTokenHandler parameterMappingHandler = new ParameterMappingTokenHandler();
  47.         GenericTokenParser genericTokenParser = new GenericTokenParser(
  48.                 "#{", "}",
  49.                 parameterMappingHandler
  50.         );
  51.         // 解析出来的sql
  52.         String parseSql = genericTokenParser.parse(sql);
  53.         // #{} 里边的参数
  54.         List<ParameterMapping> parameterMapping = parameterMappingHandler.getParameterMappings();
  55.         BoundSql boundSql = new BoundSql(parseSql, parameterMapping);
  56.         System.out.println("SimpleExecutor getBoundSql: " + boundSql.getSqlText());
  57.         return boundSql;
  58.     }
  59.     private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
  60.         if(parameterType != null){
  61.             return Class.forName(parameterType);
  62.         }
  63.         return null;
  64.     }
  65.     @Override
  66.     public void close() throws Exception {
  67.         connection.close();
  68.     }
  69. }
复制代码

类的作用

SimpleExecutor 类的主要作用是:

代码逻辑剖析


核心方法:query

实现 Executor 接口的查询功能,逻辑分为以下几步:
建立数据库毗连:
  1. connection = configuration.getDataSource().getConnection();
复制代码
获取并剖析 SQL:

创建 PreparedStatement 并绑定参数:

执行查询并处置惩罚结果集:


适用场景

该类是 MyBatis 的核心实现之一,适适用来:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4