手寫框架思路分析
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的開篇,稍後會持續更新,並且會附上手寫的源碼,敬請期待....