淺談JDBC與MyBatis
MyBatis是一個(gè)基于Java的、封裝了JDBC的持久層框架撰糠。
1 JDBC
JDBC(Java Data Base Connectivity)表示Java數(shù)據(jù)庫(kù)連接峦筒。在Java語(yǔ)言中,我們使用JDBC來(lái)操作關(guān)系型數(shù)據(jù)庫(kù)窗慎。
1.1 案例代碼
package core;
import java.sql.*;
/**
* JDBC案例類.
*
* @author 李程鵬
*/
public class JDBC {
public static void main(String[] args) {
// 定義連接對(duì)象
Connection connection = null;
// 定義預(yù)編譯語(yǔ)句對(duì)象
PreparedStatement preparedStatement = null;
// 定義結(jié)果集對(duì)象
ResultSet resultSet = null;
try {
// 加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
// 通過(guò)數(shù)據(jù)庫(kù)驅(qū)動(dòng)獲取數(shù)據(jù)庫(kù)連接
connection = DriverManager.
getConnection("jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf-8", "root", "root");
// 定義并初始化SQL語(yǔ)句
String sql = "select * from user where id = ?";
// 創(chuàng)建預(yù)編譯語(yǔ)句對(duì)象
preparedStatement = connection.prepareStatement(sql);
// 設(shè)置查詢參數(shù)
preparedStatement.setString(1, "1");
// 向數(shù)據(jù)庫(kù)發(fā)出SQL并執(zhí)行查詢,獲取查詢結(jié)果集.
resultSet = preparedStatement.executeQuery();
// 遍歷查詢結(jié)果集
while (resultSet.next()) {
// 輸出查詢結(jié)果
System.out.println("id = " + resultSet.getString("id"));
System.out.println("name = " + resultSet.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
} finally { // 釋放資源
if (resultSet != null) {
try {
// 關(guān)閉結(jié)果集對(duì)象
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
// 關(guān)閉預(yù)編譯語(yǔ)句對(duì)象
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
// 關(guān)閉連接對(duì)象
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1.2 問(wèn)題分析
上面的JDBC代碼存在以下幾個(gè)問(wèn)題:
- 頻繁地開(kāi)啟和關(guān)閉數(shù)據(jù)庫(kù)連接,嚴(yán)重地影響了數(shù)據(jù)庫(kù)的性能卤材。
- 代碼中存在硬編碼遮斥。每當(dāng)需求變更時(shí),都需要修改源代碼然后重新編譯扇丛,系統(tǒng)不易維護(hù)术吗。硬編碼的具體體現(xiàn):
- SQL語(yǔ)句中的查詢條件(String sql = "select * from user where id = ?";)。如果需求變更帆精,改為根據(jù)用戶主鍵和用戶名進(jìn)行查詢较屿,那么就需要修改源代碼。
- 設(shè)置查詢參數(shù)時(shí)的參數(shù)位置和參數(shù)值(preparedStatement.setString(1, "1");)卓练。如果SQL語(yǔ)句由于需求變更而發(fā)生變化隘蝎,那么原來(lái)編寫(xiě)的賦值語(yǔ)句就可能出錯(cuò),需要修改源代碼襟企。
- 獲取查詢結(jié)果時(shí)指定的列名(resultSet.getString("name");)嘱么。如果數(shù)據(jù)表的字段名發(fā)生了變化,那么就需要修改源代碼顽悼。
- 設(shè)置查詢參數(shù)的過(guò)程繁瑣曼振。因?yàn)樵谠O(shè)置查詢參數(shù)的過(guò)程中,需要為查詢語(yǔ)句中不同位置上的占位符設(shè)置不同的值蔚龙。
- 獲取查詢結(jié)果的過(guò)程繁瑣冰评。因?yàn)樵讷@取查詢結(jié)果的過(guò)程中,需要遍歷查詢結(jié)果集木羹,而且在遍歷的過(guò)程中還需要根據(jù)數(shù)據(jù)表的列名才可以獲取出其值甲雅。
2 MyBatis
MyBatis是一個(gè)優(yōu)秀的持久層框架,它對(duì)JDBC操作數(shù)據(jù)庫(kù)的過(guò)程進(jìn)行了封裝汇跨,使開(kāi)發(fā)者只需要關(guān)注SQL本身务荆,而不需要花費(fèi)精力去處理例如注冊(cè)驅(qū)動(dòng)、創(chuàng)建連接穷遂、創(chuàng)建執(zhí)行語(yǔ)句函匕、手動(dòng)設(shè)置參數(shù)和結(jié)果集檢索等繁雜的過(guò)程。
MyBatis通過(guò)封裝JDBC解決了它在編程中出現(xiàn)的問(wèn)題蚪黑,解決的技術(shù)方案主要有以下五種:
- 數(shù)據(jù)庫(kù)連接池盅惜。我們可以在MyBatis的全局配置文件SqlMapConfig.xml中配置數(shù)據(jù)庫(kù)連接池中剩,使用它來(lái)管理數(shù)據(jù)庫(kù)連接,這樣就可以避免由于頻繁地創(chuàng)建和釋放數(shù)據(jù)庫(kù)連接而造成的資源浪費(fèi)抒寂。
- SQL配置文件结啼。MyBatis將SQL語(yǔ)句與Java源文件進(jìn)行分離,將SQL語(yǔ)句放置到配置文件Mapper.xml中屈芜。如果有需求變更需要修改SQL語(yǔ)句郊愧,那么只需要修改配置文件即可。修改配置文件的維護(hù)成本比修改Java源文件的成本要低井佑,因?yàn)樾薷呐渲梦募笾貑⑾到y(tǒng)就可以生效属铁,但是如果修改的是Java源文件,那么就需要經(jīng)過(guò)修改躬翁、編譯焦蘑、打包、發(fā)布和重啟五個(gè)步驟盒发。
- 動(dòng)態(tài)SQL語(yǔ)句例嘱。MyBatis使用動(dòng)態(tài)SQL技術(shù)解決了JDBC編程中存在的SQL硬編碼的問(wèn)題。
- 輸入映射宁舰。MyBatis通過(guò)輸入映射技術(shù)將Java對(duì)象映射至SQL語(yǔ)句拼卵,SQL語(yǔ)句可以通過(guò)使用該Java對(duì)象取出查詢參數(shù)值,簡(jiǎn)化了JDBC中設(shè)置查詢參數(shù)的過(guò)程蛮艰。
- 輸出映射间学。MyBatis通過(guò)輸出映射技術(shù)將SQL的執(zhí)行結(jié)果映射至Java對(duì)象,省去了JDBC編程中對(duì)結(jié)果集檢索的過(guò)程印荔。