• Java精进-手写持久层框架


    前言

    本文适合有一定java基础的同学,通过自定义持久层框架,可以更加清楚常用的mybatis等开源框架的原理。

    JDBC操作回顾及问题分析

    学习java的同学一定避免不了接触过jdbc,让我们来回顾下初学时期接触的jdbc操作吧

    以下代码连接数据库查询用户表信息,用户表字段分别为用户id,用户名username。

    1. Connection connection = null;
    2. PreparedStatement preparedStatement = null;
    3. ResultSet resultSet = null;
    4. User user = new User();
    5. try {
    6. // 加载数据库驱动
    7. //Class.forName("com.mysql.jdbc.Driver");
    8. Class.forName("com.mysql.cj.jdbc.Driver");
    9. // 通过驱动管理类获取数据库链接
    10. connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mimashi3124");
    11. // 定义sql语句?表示占位符
    12. String sql = "select * from user where username = ?";
    13. // 获取预处理statement
    14. preparedStatement = connection.prepareStatement(sql);
    15. // 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值
    16. preparedStatement.setString(1, "盖伦");
    17. // 向数据库发出sql执⾏查询,查询出结果集
    18. resultSet = preparedStatement.executeQuery();
    19. // 遍历查询结果集
    20. while (resultSet.next()) {
    21. int id = resultSet.getInt("id");
    22. String username = resultSet.getString("username");
    23. // 封装User
    24. user.setId(id);
    25. user.setUsername(username);
    26. }
    27. System.out.println(user);
    28. } catch (
    29. Exception e) {
    30. e.printStackTrace();
    31. } finally {
    32. // 释放资源
    33. if (resultSet != null) {
    34. try {
    35. resultSet.close();
    36. } catch (SQLException e) {
    37. e.printStackTrace();
    38. }
    39. }
    40. if (preparedStatement != null) {
    41. try {
    42. preparedStatement.close();
    43. } catch (SQLException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. if (connection != null) {
    48. try {
    49. connection.close();
    50. } catch (SQLException e) {
    51. e.printStackTrace();
    52. }
    53. }
    54. }

    查看代码我们可以发现使用JDBC操作数据库存在以下问题:

    1. 数据库连接创建、释放频繁造成系统资源浪费,从⽽影响系统性能。
    2. Sql语句我们是写在代码里的,代码不容易维护,实际应⽤中sql变化的可能较⼤,sql变动需要改变 java代码。
    3. 使⽤preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不⼀定,可能多也可能少,修改sql还要修改代码,系统不易维护。
    4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据 库记录封装成pojo对象解析⽐较⽅便

    问题解决思路

    1. 使⽤数据库连接池初始化连接资源,避免资源浪费
    2. 将sql语句抽取到xml配置中,这种sql的变动只用关注xml文件,不比去一堆java代码里改写sql
    3. 参数硬编码问题可以使用反射、内省等技术、自动将实体与表字段进行映射。

    自己动手写个持久层框架

    接下来,我们来一个个解决上面的问题

    数据库连接池我们可以直接使用c3p0提供的ComboPooledDataSource即可

    为了解决sql硬编码问题,我们要把sql写到xml文件中,那自然是要定义一个xml文件了。

    光有sql肯定不行,毕竟我们要先连接数据库,sql语句才有存在的意义。所以xml中得先定义数据配置信息,然后才是sql语句。

    1.定义配置xml文件

    我们新建一个sqlMapConfig.xml,定义数据源信息、并且增加两个sql语句,parameterType为sql执行参数,resultType为方法返回实体。

    代码如下(数据库不同版本使用驱动类可能不同):

    1. "driverClass" value="com.mysql.cj.jdbc.Driver"/>
    2. "jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"/>
    3. "username" value="root"/>
    4. "password" value="mimashi3124"/>

    现在xml文件数据库信息也有了,sql语句定义也有了,还有什么问题呢?

    我们实际中对sql的操作会涉及到不同的表,所以我们改进一下,把每个表的sql语句单独放在一个xml里,这样结构更清晰就容易维护。

    优化以后的xml配置现在是这样了

    1. sqlMapConfig.xml
    2. "driverClass" value="com.mysql.cj.jdbc.Driver"/>
    3. "jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai"/>
    4. "username" value="root"/>
    5. "password" value="mimashi3124"/>
    6. "mapper.xml">
     
    

    mapper

  • 相关阅读:
    C语言学习之路(基础篇)—— 复合类型(自定义类型)
    【性能测试】缓慢的磁盘问题分析套路
    Spark集群的搭建
    Aspose导出word使用记录
    Kubernetes(K8S) kubesphere 安装
    ITIL-4关键词汇总
    (02)Cartographer源码无死角解析-(24) Collator类与顺序多队列类
    Spring Boot实现文件上传功能
    充分理解ADC预充电缓冲器的重要性-运放缓存
    微软宣布 S2C2F 已被 OpenSSF 采用
  • 原文地址:https://blog.csdn.net/guanshengg/article/details/126436119