远方的灯塔 - 专注于服务端技术分享 远方的灯塔 - 专注于服务端技术分享
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 《C程序设计语言》
心情随笔
  • 文章分类
  • 文章标签
  • 文章归档
友情链接
关于我
GitHub (opens new window)

Terwer Green

一个后端老菜鸟
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 《C程序设计语言》
心情随笔
  • 文章分类
  • 文章标签
  • 文章归档
友情链接
关于我
GitHub (opens new window)
  • MyBatis

    • 解析原生JDBC开发问题与优化方案
    • 自定义持久层框架的设计思路
    • 自定义持久层框架的代码实现一
    • 自定义持久层框架的代码实现二
      • 代码实现续
        • 核心执行引擎 Executor 的实现
      • 问题修复
      • 代码仓库
    • 使用getMapper方式对自定义持久层框架进行优化
    • MyBatis的基本介绍及优势
    • MyBatis的基本使用
    • Mybatis基本流程及配置文件解析
    • MyBatis复杂映射开发之一对一查询
    • MyBatis复杂映射开发之一对多查询
    • MyBatis复杂映射开发之多对多查询
    • MyBatis常用注解及基本增删改查的注解实现
    • MyBatis的注解实现复杂映射开发
    • MyBatis缓存的概念
    • 深度剖析MyBatis的一级缓存
    • 深度剖析MyBatis的二级缓存
    • MyBatis的二级缓存整合redis
    • MyBatis-RedisCache源码分析
    • MyBatis机制介绍与原理
    • 自定义MyBatis插件
    • 插件源码进一步分析与pageHelper分页插件介绍
    • 通用 Mapper 封装
    • 深入剖析MyBatis的架构原理
  • 《设计模式》

  • 后端开发
  • MyBatis
terwer
2022-08-29
目录

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

本文实现了一个简单的MyBatis框架,包括数据库连接、SQL语句解析、参数设置、结果封装等功能。具体实现包括配置文件加载、Mapper接口与SQL语句映射、动态SQL处理、连接池管理等。通过这个框架可以简化数据库操作,提高开发效率。

# 代码实现续

# 核心执行引擎 Executor 的实现

/**
 * 执行器的实现
 *
 * @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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

运行效果

​

# 问题修复

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

1
2
3
4
5
6
7
8
9
10
11
12

修正方案

​

修正后

/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
1
2
3
4
5
6
7
8
9
10
11

# 代码仓库

custom-persistence (opens new window)

文章更新历史

2024/04/24 同步文章到其他平台

2022/05/08 初稿

‍

编辑 (opens new window)
#custom#dao#framework#persistence#mybatis#mybatis-4
上次更新: 2024/06/13, 05:26:42
自定义持久层框架的代码实现一
使用getMapper方式对自定义持久层框架进行优化

← 自定义持久层框架的代码实现一 使用getMapper方式对自定义持久层框架进行优化→

最近更新
01
深入剖析MyBatis的架构原理
12-04
02
通用 Mapper 封装
10-09
03
插件源码进一步分析与pageHelper分页插件介绍
10-09
更多文章>
Theme by Vdoing | Copyright © 2011-2024 Terwer Green | MIT License | 粤ICP备2022020721号-1 | 百度统计
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式