1 JDBC操作数据库问题分析
JDBC API 允许应用程序访问任何形式的表格数据,特别是存储在关系数据库中的数据
代码示例:
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis? characterEncoding=utf-8", "root", "root"); // 定义sql语句?表示占位符 String sql = "select * from user where username = ?"; // 获取预处理statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值 preparedStatement.setString(1, "tom"); // 向数据库发出sql执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { int id = resultSet.getInt("id"); String username = resultSet.getString("username"); // 封装User user.setId(id); user.setUsername(username); } System.out.println(user); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
2 JDBC问题分析和解决思路
剖开代码,逐个分析:
(1)加载驱动,获取链接:
- 存在问题1:数据库配置信息存在硬编码问题。
优化思路:使用配置文件!
- 存在问题2:频繁创建、释放数据库连接问题。
优化思路:使用数据连接池!
(2)定义sql、设置参数、执行查询:
- 存在问题3:SQL语句、设置参数、获取结果集参数均存在硬编码问题 。
优化思路:使用配置文件!
(2)遍历查询结果集:
- 存在问题4:手动封装返回结果集,较为繁琐
优化思路:使用Java反射、内省!
针对JDBC各个环节中存在的不足,现在,我们整理出对应的优化思路,统一汇总:
存在问题 | 优化思路 |
数据库配置信息存在硬编码问题 | 使用配置文件 |
频繁创建、释放数据库连接问题 | 使用数据连接池 |
SQL语句、设置参数、获取结果集参数均存在硬编码问题 | 使用配置文件 |
手动封装返回结果集,较为繁琐 | 使用Java反射、内省 |
3 自定义持久层框架_思路分析
JDBC是个人作战,凡事亲力亲为,低效而高险,自己加载驱动,自己建连接,自己 …
而持久层框架好比是多工种协作,分工明确,执行高效,有专门负责解析注册驱动建立连接的,有专门管理数据连接池的,有专门执行sql语句的,有专门做预处理参数的,有专门装配结果集的 …
优化思路: 框架的作用,就是为了帮助我们减去繁重开发细节与冗余代码,使我们能更加专注于业务应用开发。
3.1 使用JDBC和使用持久层框架区别
是不是发现,拥有这么一套持久层框架是如此舒适,我们仅仅需要干两件事:
- 配置数据源(地址/数据名/用户名/密码)
- 编写SQL与参数准备(SQL语句/参数类型/返回值类型)
框架,除了思考本身的工程设计,还需要考虑到实际项目端的使用场景,干系方涉及两端:
- 使用端(实际项目)
- 持久层框架本身
以上两步,我们通过一张架构图《 手写持久层框架基本思路 》来梳理清楚:
3.2 核心接口/类重点说明
分工协作 | 角色定位 | 类名定义 |
负责读取配置文件 | 资源辅助类 | Resources |
负责存储数据库连接信息 | 数据库资源类 | Configuration |
负责存储SQL映射定义、存储结果集映射定义 | SQL与结果集资源类 | MappedStatement |
负责解析配置文件,创建会话工厂SqlSessionFactory | 会话工厂构建者 | SqlSessionFactoryBuilder |
负责创建会话SqlSession | 会话工厂 | SqlSessionFactory |
指派执行器Executor | 会话 | SqlSession |
负责执行SQL (配合指定资源Mapped Statement) | 执行器 | Executor |
正常来说项目只对应一套数据库环境,一般对应一个SqlSessionFactory实例对象,我们使用单例模式只创建一个SqlSessionFactory实例。如果需要配置多套数据库环境,那需要做一些拓展,例如Mybatis中通过environments等配置就可以支持多套测试/生产数据库环境进行切换。
3.3 项目使用端
(1)调用框架API,除了引入自定义持久层框架的jar包
(2)提供两部分配置信息:1.sqlMapConfig.xml : 数据库配置信息(地址/数据名/用户名/密码),以及mapper.xml的全路径
2.mapper.xml : SQL配置信息,存放SQL语句、参数类型、返回值类型相关信息
3.4 自定义框架本身
1、加载配置文件:根据配置文件的路径,加载配置文件成字节输入流,存储在内存中。
2、 创建两个javaBean(容器对象):存放配置文件解析出来的内容
3、解析配置文件(使用dom4j) ,并创建SqlSession会话对象
4、创建SqlSessionFactory接口以及实现类DefaultSqlSessionFactory
5、创建SqlSession接口以及实现类DefaultSqlSession
6、创建Executor接口以及实现类SimpleExecutor
基本过程我们已经清晰,我们再细化一下类图,更好的助于我们实际编码:
3.5 最终手写的持久层框架结构参考