首页 > 其他分享 >自定义持久层框架的代码实现二

自定义持久层框架的代码实现二

时间:2022-08-30 00:04:49浏览次数:111  
标签:username parameterType 持久 框架 val String sql id 自定义

代码实现续

核心执行引擎Executor的实现

/**
 * 执行器的实现
 *
 * @name: SimpleExecutor
 * @author: terwer
 * @date: 2022-05-08 16:53
 */
class SimpleExecutor : Executor {
    @Throws(Exception::class)
    override fun <E> query(
        configuration: Configuration,
        mappedStatement: MappedStatement,
        vararg params: Any
    ): List<E> {
        // 注册驱动,获取链接
        val connection = configuration.dataSource.connection

        // 获取sql语句
        // 获取的sql
        // select * from user where id = #{id} and username = #{username}
        // 转换后的sql
        // select * from user where id = ? and username = ?
        val sql = mappedStatement.sql

        // 转换sql语句
        val boundSql = getBoundSql(sql)

        // 获取预处理对象
        val preparedStatement = connection.prepareStatement(boundSql.sqlText)

        // 设置参数
        // 参数全路径
        val parameterType = mappedStatement.parameterType
        val parameterClass = getClassType(parameterType)
        val parameterMappingList = boundSql.parameterMappingList
        for (i in parameterMappingList.indices) {
            val parameterMapping = parameterMappingList[i]
            val content = parameterMapping.content
            val field = parameterClass!!.getDeclaredField(content)
            field.isAccessible = true
            val value = field[params[0]]
            preparedStatement.setObject(i + 1, value)
        }

        // 执行sql
        val resultSet = preparedStatement.executeQuery()
        val returnType = mappedStatement.resultType
        val resultTypeClass = getClassType(returnType)
        val objects = ArrayList<Any>()

        // 封装返回结果集
        while (resultSet.next()) {
            val o = resultTypeClass!!.newInstance()
            val metaData = resultSet.metaData
            for (i in 1..metaData.columnCount) {
                val columnName = metaData.getColumnName(i)
                // 获取字段值
                val value = resultSet.getObject(columnName)

                // 使用反射或者内省,根据数据库表和实体的对应关系完成封装
                val propertyDescriptor = PropertyDescriptor(columnName, resultTypeClass)
                val writeMethod = propertyDescriptor.writeMethod
                writeMethod.invoke(o, value)
            }
            objects.add(o)
        }
        return objects as List<E>
    }

    @Throws(ClassNotFoundException::class)
    private fun getClassType(parameterType: String?): Class<*>? {
        return if (parameterType != null) {
            Class.forName(parameterType)
        } else null
    }

    /**
     * 1、将#{}使用?代替
     * 2、解析出#{}的值进行存储
     *
     * @param sql
     * @return
     */
    private fun getBoundSql(sql: String): BoundSql {
        // 标记处理类,配合标记解析器完成对占位符的解析
        val tokenHandler = ParameterMappingTokenHandler()
        val genericTokenParser = GenericTokenParser("#{", "}", tokenHandler)

        // 解析后的sql
        val parseSql = genericTokenParser.parse(sql)
        // 解析的参数名称
        val parameterMappings = tokenHandler.parameterMappings
        return BoundSql(parseSql, parameterMappings)
    }
}
/**
 * 执行器的实现
 *
 * @name: SimpleExecutor
 * @author: terwer
 * @date: 2022-03-14 16:53
 **/
public class SimpleExecutor implements Executor {
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        // 注册驱动,获取链接
        Connection connection = configuration.getDataSource().getConnection();

        // 获取sql语句
        // 获取的sql
        // select * from user where id = #{id} and username = #{username}
        // 转换后的sql
        // select * from user where id = ? and username = ?
        String sql = mappedStatement.getSql();

        // 转换sql语句
        BoundSql boundSql = getBoundSql(sql);

        // 获取预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        // 设置参数
        // 参数全路径
        String parameterType = mappedStatement.getParameterType();
        Class<?> parameterClass = getClassType(parameterType);

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();

            Field field = parameterClass.getDeclaredField(content);
            field.setAccessible(true);
            Object value = field.get(params[0]);

            preparedStatement.setObject(i + 1, value);
        }

        // 执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        String returnType = mappedStatement.getResultType();
        Class<?> resultTypeClass = getClassType(returnType);
        Object o = resultTypeClass.newInstance();
        ArrayList<Object> objects = new ArrayList<>();

        // 封装返回结果集
        while (resultSet.next()) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                String columnName = metaData.getColumnName(i);
                // 获取字段值
                Object value = resultSet.getObject(columnName);

                // 使用反射或者内省,根据数据库表和实体的对应关系完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            objects.add(o);
        }

        return (List<E>) objects;
    }

    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (parameterType != null) {
            Class<?> aClass = Class.forName(parameterType);
            return aClass;
        }
        return null;
    }

    /**
     * 1、将#{}使用?代替
     * 2、解析出#{}的值进行存储
     *
     * @param sql
     * @return
     */
    private BoundSql getBoundSql(String sql) {
        // 标记处理类,配合标记解析器完成对占位符的解析
        ParameterMappingTokenHandler tokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", tokenHandler);

        // 解析后的sql
        String parseSql = genericTokenParser.parse(sql);
        // 解析的参数名称
        List<ParameterMapping> parameterMappings = tokenHandler.getParameterMappings();

        BoundSql boundSql = new BoundSql(parseSql, parameterMappings);

        return boundSql;
    }
}

运行效果

问题修复

1、selectList打印的全部是同一个值

/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/bin/java -... com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.terwergreen.test.IPersistenceTest,test2
Connected to the target VM, address: '127.0.0.1:50317', transport: 'socket'
log4j:WARN No appenders could be found for logger (com.mchange.v2.log.MLog).
log4j:WARN Please initialize the log4j system properly.
User{id=5, username='dali'}
User{id=5, username='dali'}
User{id=5, username='dali'}
User{id=5, username='dali'}
Disconnected from the target VM, address: '127.0.0.1:50317', transport: 'socket'

Process finished with exit code 0

修正方案

修正后

/Library/Java/JavaVirtualMachines/jdk1.8.0_291.jdk/Contents/Home/bin/java -... com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.terwergreen.test.IPersistenceTest,test2
Connected to the target VM, address: '127.0.0.1:50820', transport: 'socket'
log4j:WARN No appenders could be found for logger (com.mchange.v2.log.MLog).
log4j:WARN Please initialize the log4j system properly.
User{id=1, username='tyw'}
User{id=2, username='张月'}
User{id=4, username='haha'}
User{id=5, username='dali'}
Disconnected from the target VM, address: '127.0.0.1:50820', transport: 'socket'

Process finished with exit code 0

代码仓库

custom-persistence

文章更新历史

2022/05/08 feat:增加Kotlin实现。

标签:username,parameterType,持久,框架,val,String,sql,id,自定义
From: https://www.cnblogs.com/tangyouwei/p/code-implementation-of-custom-persistence-layer-frame

相关文章

  • 自定义持久层框架的代码实现二
    代码实现续核心执行引擎Executor的实现/***执行器的实现**@name:SimpleExecutor*@author:terwer*@date:2022-05-0816:53*/classSimpleExecutor......
  • 自定义持久层框架的代码实现二
    代码实现续核心执行引擎Executor的实现/***执行器的实现**@name:SimpleExecutor*@author:terwer*@date:2022-05-0816:53*/classSimpleExecutor......
  • 前端页面框架
    目录jQuery框架操作jQuery事件动画效果Bootstrap框架jQuery框架操作1.筛选器方法1.1下一个元素:next、nextAll($("#id").)nextUntil($("#id").nextUntil("#i2")两个指定......
  • 大数据技术Flume框架详解
    Flume的概述Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构,灵活简单。高可用(HA)flume框架(故障转移机制)高......
  • 第二章、框架设计的核心要素
    1.提升用户的开发体验开发体验是衡量一个框架的指标之一关于快速定位问题和打印警告信息和其他重要信息 Vue.js3  源码中使用 init......
  • APICloud AVM框架 封装车牌号输入键盘组件
    AVM(Application-View-Model)前端组件化开发模式基于标准WebComponents组件化思想,提供包含虚拟DOM和Runtime的编程框架avm.js以及多端统一编译工具,完全兼容WebComponents标......
  • TDesign组件库 小程序组件怎么自定义CSS样式
    不知道有没有人跟我有同样的疑问,看了几遍文档后我懂了Html代码<t-searchclass="searchBox"model:value="{{searchVal}}"placeholder="请输入要查询的商品名称"/......
  • 如何将本地化添加到 Django REST 框架
    如何将本地化添加到DjangoREST框架Django在本文中,我将为您提供有关如何使用I18N和DjangoRestFramework本地化DjangoRestAPI的指南。在开始本教程之前,我将......
  • 自定义View3-水波纹扩散(仿支付宝咻一咻)实现代码、思想
    PS:自定义view篇-水波纹实现效果:水波纹扩散场景:雷达、按钮点击效果、搜索等实现:先上效果图,之前记得支付宝有一个咻一咻,当时就是水波纹效果,实现起来一共两步,第一画内圆,......
  • 微信小程序自定义picker触发区域
    <!--wxml--><pickerbindchange="changePicker"value="{{i}}"range="{{list}}"><!--注意这一层不能少,否则弹性布局失效--><viewclass="jcsb"><viewcla......