????之前在面試工作的時候,我當時用的是hibernate,但是現在互聯網項目并發量大,一般都會選擇使用Mybatis,于是自己把Mybatis學習了,因為之前有hibernate的底子,相比較hibernate簡單的多,但是對sql編寫的能力要求高。在使用起來各有各的好處吧,在下面的筆記中,我也寫了一些關于他們兩者的區別。個人建議如果有時間的話,把hibernate和Mybatis都學習一下,這樣對你的幫助也許會更大。
1.Mybatis的簡單介紹
MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。??? MyBatis是一個優秀的持久層框架,它對jdbc的操作數據庫的過程進行封裝,使開發者只需要關注SQL 本身,而不需要花費精力去處理例如注冊驅動、創建connection、創建statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。
Mybatis通過xml或注解的方式將要執行的各種statement(statement、preparedStatement、CallableStatement)配置起來,并通過java對象和statement中的sql進行映射生成最終執行的sql語句,最后由mybatis框架執行sql并將結果映射成java對象并返回。
2.關于使用JDBC以及問題總結
--jdbc編程步驟:
1.加載數據庫驅動
2.創建并獲取數據庫鏈接
3.創建jdbc statement對象
4.設置sql語句
5.設置sql語句中的參數(使用preparedStatement)
6.通過statement執行sql并獲取結果
7.對sql執行結果進行解析處理
8.釋放資源(resultSet、preparedstatement、connection)
--jdbc程序
public static void main(String[] args) {
??? ?????? Connection connection =null;
?????????? PreparedStatementpreparedStatement =null;
?????????? ResultSetresultSet =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,"王五");
????????????? //向數據庫發出sql執行查詢,查詢出結果集
????????????? resultSet=? preparedStatement.executeQuery();
????????????? //遍歷查詢結果集
????????????? while(resultSet.next()){
????????????????? System.out.println(resultSet.getString("id")+"? "+resultSet.getString("username"));
????????????? }
?????????? }catch (Exception e) {
????????????? e.printStackTrace();
?????????? }finally{
????????????? //釋放資源
????????????? if(resultSet!=null){
????????????????? try {
???????????????????? resultSet.close();
????????????????? }catch (SQLException e) {
???????????????????? // TODO Auto-generated catch block
????????????????? ??? e.printStackTrace();
????????????????? }
????????????? }
????????????? if(preparedStatement!=null){
????????????????? try {
???????????????????? preparedStatement.close();
????????????????? }catch (SQLException e) {
???????????????????? // TODO Auto-generated catch block
???????????????????? e.printStackTrace();
????????????????? }
????????????? }
????????????? if(connection!=null){
????????????????? try {
???????????????????? connection.close();
????????????????? }catch (SQLException e) {
???????????????????? // TODO Auto-generated catch block
???????????????????? e.printStackTrace();
????????????????? }
????????????? }
?????????? }
?????? }
--問題總結
1、 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。
2、 Sql語句在代碼中硬編碼,造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
3、 使用preparedStatement向占有位符號傳參數存在硬編碼,因為sql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統不易維護。
4、 對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化,系統不易維護,如果能將數據庫記錄封裝成pojo對象解析比較方便。?
引出Mybatis,這里使用了一個案例入門
3.Mybatis的架構圖
1、 mybatis配置 SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運行環境等信息。 mapper.xml文件即sql映射文件,文件中配置了操作數據庫的sql語句。此文件需要在SqlMapConfig.xml中加載。
2、 通過mybatis環境等配置信息構造SqlSessionFactory即會話工廠
3、 由會話工廠創建sqlSession即會話,操作數據庫需要通過sqlSession進行。
4、 mybatis底層自定義了Executor執行器接口操作數據庫,Executor接口有兩個實現,一個是基本執行器、一個是緩存執行器。
5、 Mapped Statement也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個Mapped Statement對象,sql的id即是Mapped statement的id。
6、 Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql前將輸入的java對象映射至sql中,輸入參數映射就是jdbc編程中對preparedStatement設置參數。
7、 Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql后將輸出結果映射至java對象中,輸出結果映射過程相當于jdbc編程中對結果的解析處理過程。
4.Mybatis案例入門
4.1 需求:
實現以下功能:
根據用戶id查詢一個用戶信息
根據用戶名稱模糊查詢用戶信息列表
添加用戶? ? 更新用戶? ? 刪除用戶?
4.2 項目工程的搭建:
第一步:創建Java工程
第二步:加入jar包(mybatis核心包、依賴包、數據驅動包)
第三步:在classpath下創建log4j.properties(mybatis默認使用log4j作為輸出日志信息)
第四步:在classpath下創建SqlMapConfig.xml(SqlMapConfig.xml是mybatis核心配置文件,上邊文件的配置內容為數據源、事務管理)
第五步:po類(Po類作為mybatis進行sql映射使用,po類通常與數據庫表對應)
第六步:sql映射文件
第七步:加載映射文件(mybatis框架需要加載映射文件,將Users.xml添加在SqlMapConfig.xml)
4.3 根據id查詢用戶信息
4.3.1?user.xml映射文件
parameterType:定義輸入到sql中的映射類型
#{id}表示使用preparedstatement設置占位符號并將輸入變量id傳到sql
resultType:定義結果映射類型
4.3.2?測試程序
4.4?根據用戶名查詢用戶信息
4.4.1?映射文件(user.xml)
4.4.2?測試程序
4.5?上面4.3和4.4的小結
4.5.1 #{}和${}
#{}表示一個占位符號,通過#{}可以實現preparedStatement向占位符中設置值,自動進行java類型和jdbc類型轉換,#{}可以有效防止sql注入。 #{}可以接收簡單類型值或pojo屬性值。 如果parameterType傳輸單個簡單類型值,#{}括號中可以是value或其它名稱。
${}表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc類型轉換, ${}可以接收簡單類型值或pojo屬性值,如果parameterType傳輸單個簡單類型值,${}括號中只能是value。
4.5.2 parameterType和resultType
parameterType:指定輸入參數類型,mybatis通過ognl從輸入對象中獲取參數值拼接在sql中。 resultType:指定輸出結果類型,mybatis將sql查詢結果的一行記錄數據映射為resultType指定類型的對象。
4.5.3?selectOne和selectList
selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則拋出異常: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3 ??? at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70) ?
selectList可以查詢一條或多條記錄。
4.6?添加用戶
4.6.1?映射文件
4.6.2?測試程序
4.7?mysql自增主鍵返回(通過修改sql映射文件,可以將mysql自增主鍵返回)
添加selectKey實現將主鍵返回
keyProperty:返回的主鍵存儲在pojo中的哪個屬性
order:selectKey的執行順序,是相對與insert語句來說,由于mysql的自增原理執行完insert語句之后才將主鍵生成,所以這里selectKey的執行順序為after resultType:返回的主鍵是什么類型
LAST_INSERT_ID():是mysql的函數,返回auto_increment自增列新記錄id值。
--使用 uuid實現主鍵
4.8?刪除用戶
4.8.1?映射文件
4.8.2?測試程序
4.9?修改用戶
4.9.1?映射文件
4.9.2?測試程序
5??Mybatis解決jdbc編程的問題
1、 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理數據庫鏈接。
2、 Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3、 向sql語句傳參數麻煩,因為sql語句的where條件不一定,可能多也可能少,占位符需要和參數一一對應。
解決:Mybatis自動將java對象映射至sql語句,通過statement中的parameterType定義輸入參數的類型。 4、 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執行結果映射至java對象,通過statement中的resultType定義輸出結果的類型。
6?原始Dao開發方式(需要編寫Dao接口和Dao實現類)
6.1?映射文件
6.2?Dao接口及實現類
--接口
--實現類
6.3?測試
6.4?問題
原始Dao開發中存在以下問題:
1.Dao方法體存在重復代碼:通過SqlSessionFactory創建SqlSession,調用SqlSession的數據庫操作方法
2.調用sqlSession的數據庫操作方法需要指定statement的id,這里存在硬編碼,不利于開發維護。
7?Mapper動態代理方式(重要)
7.1?開發規范
Mapper接口開發方法只需要程序員編寫Mapper接口(相當于Dao接口),由Mybatis框架根據接口定義創建接口的動態代理對象,代理對象的方法體同上邊Dao接口實現類方法。
Mapper接口開發需要遵循以下規范:
1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
2、 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
3、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
4、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同
7.2?Mapper.xml(映射文件)
定義mapper映射文件UserMapper.xml(內容同Users.xml),需要修改namespace的值為 UserMapper接口路徑。將UserMapper.xml放在classpath 下mapper目錄 下。
7.3?接口文件(Mapper.java)
--接口定義的規則:
1、 Mapper接口方法名和Mapper.xml中定義的statement的id相同
2、 Mapper接口方法的輸入參數類型和mapper.xml中定義的statement的parameterType的類型相同
3、 Mapper接口方法的輸出參數類型和mapper.xml中定義的statement的resultType的類型相同
7.4?加載UserMapper.xml文件(修改SqlMapConfig.xml文件)
7.5?測試
8 Mybatis和hibernate的區別
Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句,不過mybatis可以通過XML或注解方式靈活配置要運行的sql語句,并將java對象和sql語句映射生成最終執行的sql,最后將sql執行的結果再映射生成java對象。
Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關系數據模型要求不高的軟件開發,例如互聯網軟件、企業運營類軟件等,因為這類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套sql映射文件,工作量大。
Hibernate對象/關系映射能力強,數據庫無關性好,對于關系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎么設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。
總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合才是最好。