手写框架思路分析
Mybatis其实就是封装了JDBC的持久层框架
JDBC原生代码分析
JDBC原生代码
@Test
public void test() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库链接connection = DriverManager
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, "王五");
// 向数据库发出 sql 执行查询,查询出结果集
rs = preparedStatement.executeQuery();
// 遍历查询结果集
while (rs.next()) {
System.out.println(rs.getString("id") + " " + rs.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (rs != null) {
try {
rs.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) {
// TODO Auto-generated catch block e.printStackTrace();
}
}
}
}
分析原生代码的问题
-
存在硬编码
解决方案:使用配置文件配置(数据库驱动信息、数据库连接信息、sql语句信息、参数信息),但是这些配置不属于一个维度,所以要分开配置即:
全局配置文件(数据库驱动信息、数据库连接信息等运行时信息)
映射文件(配置和业务相关的sql语句等信息)
-
数据库连接再频繁的开启和关闭
解决方案:使用连接池 c3p0、dbcp等
根据上述JDBC代码可以得到以下改进需求:
-
程序员要通过调用简单的接口,就可以完成CRUD操作。SqlSession接口(对程序员提供CRUD的api)
接口的底层实现,不需要程序员关系(使用JDBC完成CRUD)
-
jdbc代码应该如何去解决创建连接和处理业务这个问题
创建连接的部分
执行statement处理部分
根据JDBC原生代码分析可以得到一下方案
整个的mybatis就关心两个流程:配置文件的加载流程、sqlsession(statement)执行流程
- 全局配置文件
<configuration>
<!-- mybatis 数据源环境配置 -->
<environments default="dev">
<environment id="dev">
<!-- 配置数据源信息 -->
<dataSource type="DBCP">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!-- 映射文件加载 -->
<mappers>
<!-- resource指定映射文件的类路径 -->
<mapper resource="mapper/UserMapper.xml"></mapper>
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
</mappers>
</configuration>
- 映射文件
<mapper namespace="test">
<!-- select标签,封装了SQL语句信息、入参类型、结果映射类型 -->
<select id="findUserById"
parameterType="com.kkb.mybatis.po.User"
resultType="com.kkb.mybatis.po.User" statementType="prepared">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
- 配置文件的加载思路
1. 指定全局配置文件的路径
2. 根据路径去读取配置文件到内存中(InputStream)
3. 通过dom解析,去读取InputStream流,然后获取一个Document对象(封装了整个全局配置文件和映射文件的信息)。
4. 对Document对象按照mybatis的标签语义进行解析------->Configuration对象(封装了整个全局配置文件和映射文件的信息)。
5. 解析全局配置文件的时候,也会解析映射文件
主要解析的就是映射文件中的四个标签(select\insert\update\delete)------解析成一个对象MappedStatement
MappedStatement对象应该存储哪些信息呢?sql语句、入参的java类型、结果映射的类型、statement的类型
- jdbc的执行思路(sqlsession(statement)执行流程):
1. 获取连接(连接时配置到xml文件中的)
2. 获取sql语句(sql语句也在xml文件中)
3. 创建statement
通过xml中的信息获取statement的类型(应该创建哪种statement:statement、preparedstatement\callableStatement)
4. 设置参数
多个参数应该如何赋值,因为入参只有一个,但是sql语句中可能需要多个参数值
5. 执行statement
6. 结果映射
对resultset进行处理,可以获取里面的列名,我们就可以找一个映射的java类型进行结果映射
总结
以上是整篇手写Mybatis的开篇,稍后会持续更新,并且会附上手写的源码,敬请期待....