1、框架介紹:java
MyBatis是一個優秀的持久層框架,它對jdbc的操做數據庫的過程進行封裝,使開發者只須要關注 SQL 自己,而不須要花費精力去處理例如註冊驅動、建立connection、建立statement、手動設置參數、結果集檢索等jdbc繁雜的過程代碼。mysql
Mybatis經過xml或註解的方式將要執行的各類statement(statement、preparedStatemnt、CallableStatement---java中調存儲過程)配置起來,並經過java對象和statement中的sql進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射成java對象並返回。程序員
2、對比下,JDBC存在的問題:spring
一、 數據庫鏈接建立、釋放頻繁形成系統資源浪費,從而影響系統性能。若是使用數據庫鏈接池可解決此問題。sql
二、 Sql語句在代碼中硬編碼,形成代碼不易維護,實際應用中sql變化的可能較大,sql變更須要改變java代碼。數據庫
三、 使用preparedStatement向佔位符號傳參數存在硬編碼,由於sql語句的where條件不必定,可能多也可能少,修改sql還要修改代碼,系統不易維護。apache
四、對結果集解析存在硬編碼(查詢列名),sql變化致使解析代碼變化,系統不易維護,若是能將數據庫記錄封裝成pojo對象解析比較方便。編程
3、架構:緩存
一、 mybatis配置安全
SqlMapConfig.xml,此文件做爲mybatis的全局配置文件,配置了mybatis的運行環境等信息。------一個表對應一個XML!!
mapper.xml文件即sql映射文件,文件中配置了操做數據庫的sql語句。此文件須要在SqlMapConfig.xml中加載。
二、 經過mybatis環境等配置信息構造SqlSessionFactory即會話工廠
三、 由會話工廠建立sqlSession即會話,操做數據庫須要經過sqlSession進行。
四、 mybatis底層自定義了Executor執行器接口操做數據庫,Executor接口有兩個實現,一個是基本執行器、一個是緩存執行器。
五、 Mapped Statement(負責接收輸入映射並輸出輸出映射)也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個Mapped Statement對象,sql的id便是Mapped statement的id。
六、 Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor經過Mapped Statement在執行sql前將輸入的java對象映射至sql中,輸入參數映射就是jdbc編程中對preparedStatement設置參數。
七、 Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor經過Mapped Statement在執行sql後將輸出結果映射至java對象中,輸出結果映射過程至關於jdbc編程中對結果的解析處理過程。
4、配置:
一、加入mybatis核心包、依賴包、數據驅動包:
二、建立:
建立資源文件夾(source Folder是個資源文件夾:資源文件夾被引用是不須要加文件名,是默認的根目錄的!)config,加入log4j.properties和SqlMapConfig.xml配置文件
log4j.properties:
mybatis默認使用log4j做爲輸出日誌信息。
# Global logging configuration log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
SqlMapConfig.xml:(已進行最後的配置修改)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- properties是屬性-這個地址(source file類型的)是資源文件夾,不須要寫src ,--> <properties resource="db.properties"></properties> <!-- 配置別名 不區分大小寫--> <typeAliases> <!--<typeAlias alias="user" type="com.oracle.pojo.User"/>--> <!-- 將pojo裏的全部類配置別名 --> <package name="com.oracle.pojo"/> </typeAliases> <!--environments 環境集合屬性對象:單獨使用此框架的時候使用, 和spring整合後 environments配置將廢除 --> <environments default="development">
<!-- environment環境子屬性對象 --> <environment id="development"> <!-- transactionManager:事務管理-使用jdbc事務管理 --> <transactionManager type="JDBC" /> <!-- dataSource:數據源-數據庫鏈接池 --> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <!-- mappers映射器 必須掌握--> <mappers> <!-- <mapper resource="com/oracle/mapper/UserMapper.xml"/> 原來的寫法 <mapper class="com.oracle.mapper.UserMapper"/> 使用mapper接口類路徑。。。下面是註冊指定包下的全部mapper接口 --> <package name="com.oracle.mapper"/> </mappers> </configuration>
建立pojo類:
package com.oracle.pojo; public class Orders { private Integer id; private Integer userId; private String number; private String createtime; private String note; private User user;//一對一的話直接私有個類,一對多就得List<User> public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getCreatetime() { return createtime; } public void setCreatetime(String createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime + ", note=" + note + ", user=" + user + "]"; } }
在config下的sqlmap目錄下建立sql映射文件User.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 必須掌握-->
<!-- namespace:命名空間,用於隔離sql -->
<mapper namespace="com.oracle.mapper.OrdersMapper">
<resultMap type="orders" id="getOrders">
<!-- <id property="id" column="id"/> -->
<result property="userId" column="user_id"/>
</resultMap>
<!--查詢全部訂單信息 -->
<!-- id:statement的id 或者叫作sql的id-->
<!-- parameterType:聲明輸入參數的類型 -->
<!-- resultType:聲明輸出結果的類型,應該填寫pojo的全路徑 -->
<!-- #{}:輸入參數的佔位符,至關於jdbc的? -->
<select id="getAllOrders" resultMap="getOrders"> select * from orders </select> <!--查詢全部的訂單信息以及其關聯的用戶信息 --> <!-- 由於兩個表是一對一!爲使用resultMap,因此在orders下添加私有的User類對應的user屬性,由於沒法將數據映射到user裏面 因此開始下面的手動映射 --> <resultMap type="orders" id="orderUserResultMap"> <id property="id" column="id" /> <result property="userId" column="user_id" /> <result property="number" column="number" /> <result property="createtime" column="createtime" /> <result property="note" column="note" /> <!-- association :配置一對一屬性 --> <!-- property:order裏面的User屬性名 --> <!-- javaType:屬性類型 --> <association property="user" javaType="user"> <!-- id:聲明主鍵,表示user_id是關聯查詢對象的惟一標識--> <id property="id" column="user_id" /> <result property="username" column="username" /> <result property="address" column="address" /> </association> </resultMap> <!-- 一對一關聯,查詢訂單,訂單內部包含用戶屬性 --> <select id="getOrdersUser" resultMap="orderUserResultMap"> SELECT o.id, o.user_id userId, o.number, o.createtime, o.note, u.username, u.address FROM `orders` o LEFT JOIN `user` u ON o.user_id = u.id </select> </mapper>
mybatis框架須要加載Mapper.xml映射文件,將users.xml添加在SqlMapConfig.xml:(上圖已添加)
測試下:
// 查詢全部的訂單及用戶信息 public static void method02() throws IOException { // 1. 建立SqlSessionFactoryBuilder對象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 2. 加載SqlMapConfig.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 3. 建立SqlSessionFactory對象 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 4. 建立SqlSession對象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 5.執行sql OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);// 得到一個(動態代理)UserMapper接口的實現類對象 List<Orders> list = ordersMapper.getOrdersUser(); System.out.println(list); // 6.釋放資源 sqlSession.close(); }
5、小結:
#{}表示一個佔位符號?,經過#{}能夠實現preparedStatement向佔位符中設置值,自動進行java類型和jdbc類型轉換。#{}能夠有效防止sql注入。 #{}能夠接收簡單類型值或pojo屬性值。 若是parameterType傳輸單個簡單類型值,#{}括號中能夠是value或其它名稱。
${}表示拼接sql串(拼串就能引發注入),經過${}能夠將parameterType 傳入的內容拼接在sql中且不進行jdbc類型轉換, ${}能夠接收簡單類型值或pojo屬性值,若是parameterType傳輸單個簡單類型值,${}括號中只能是value。
parameterType:指定輸入參數類型,mybatis經過ognl從輸入對象中獲取參數值拼接在sql中。
resultType:指定輸出結果類型,mybatis將sql查詢結果的一行記錄數據映射爲resultType指定類型的對象。若是有多條數據,則分別進行映射,並把對象放到容器List中(寫泛型)
6、Mybatis解決jdbc編程的問題:
一、 數據庫鏈接建立、釋放頻繁形成系統資源浪費從而影響系統性能,若是使用數據庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數據鏈接池,使用鏈接池管理數據庫連接。
二、 Sql語句寫在代碼中形成代碼不易維護,實際應用sql變化的可能較大,sql變更須要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
三、 向sql語句傳參數麻煩,由於sql語句的where條件不必定,可能多也可能少,佔位符須要和參數一一對應。
解決:Mybatis自動將java對象映射至sql語句,經過statement中的parameterType定義輸入參數的類型。
四、 對結果集解析麻煩,sql變化致使解析代碼變化,且解析前須要遍歷,若是能將數據庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執行結果映射至java對象,經過statement中的resultType定義輸出結果的類型。
7、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須要具備很強的經驗和能力才行。
總之,按照用戶的需求在有限的資源環境下只要能作出維護性、擴展性良好的軟件架構都是好架構,因此框架只有適合纔是最好。
8、Dao開發方法:
原始Dao開發方法和Mapper動態代理開發方法。
(一)、sqlsession:
一、SqlSession中封裝了對數據庫的操做,如:查詢、插入、更新、刪除等。
SqlSession經過SqlSessionFactory建立。
SqlSessionFactory是經過SqlSessionFactoryBuilder進行建立。
二、SqlSessionFactoryBuilder用於建立SqlSessionFacoty,SqlSessionFacoty一旦建立完成就不須要SqlSessionFactoryBuilder了,由於SqlSession是經過SqlSessionFactory建立的。因此能夠將SqlSessionFactoryBuilder當成一個工具類使用,最佳使用範圍是方法範圍即方法體內局部變量。
三、SqlSessionFactory是一個接口,接口中定義了openSession的不一樣重載方法,SqlSessionFactory的最佳使用範圍是整個應用運行期間,一旦建立後能夠重複使用,一般以單例模式管理SqlSessionFactory。
四、SqlSession是一個面向用戶的接口,sqlSession中定義了數據庫操做方法。
每一個線程都應該有它本身的SqlSession實例。SqlSession的實例不能共享使用,它也是線程不安全的。所以最佳的範圍是請求或方法範圍。絕對不能將SqlSession實例的引用放在一個類的靜態字段或實例字段中。
(二)、原始Dao開發方法須要程序員編寫Dao接口和Dao實現類。
原始Dao開發中存在如下問題:
一、 Dao方法體存在重複代碼:經過SqlSessionFactory建立SqlSession,調用SqlSession的數據庫操做方法
二、 調用sqlSession的數據庫操做方法須要指定statement的id,這裏存在硬編碼,不便於開發維護。
(三)、Mapper:動態代理!!!
Mapper接口開發方法只須要程序員編寫Mapper接口(至關於Dao接口),由Mybatis框架根據接口定義建立接口的動態代理對象(一個接口的實現類對象),代理對象的方法體同上邊Dao接口實現類方法。
Mapper接口開發須要遵循如下規範:
一、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
二、 Mapper接口方法名和Mapper.xml中定義的每一個statement的id相同
三、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每一個sql 的parameterType的類型相同
四、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每一個sql的resultType的類型相同
package com.oracle.mapper; import java.util.List; import com.oracle.pojo.Query; import com.oracle.pojo.QueryVo; import com.oracle.pojo.User; public interface UserMapper { // Mapper接口開發須要遵循如下規範: //一、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。 //二、 Mapper接口方法名和Mapper.xml中定義的每一個statement的id相同 //三、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每一個sql 的parameterType的類型相同 //四、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每一個sql的resultType的類型相同 //一個新的--建立一個xml文件和接口!xml裏面配置接口的地址(包+類)<mapper namespace="com.oracle.mapper.UserMapper"> // 根據id查詢User public User getUserById(Integer id); //根據用戶名模糊查詢用戶列表 public List<User> getUserByUserName(String username); //新增用戶 public void addUser(User user); //刪除用戶 public void deleteUser(Integer id); //修改用戶 public void updateUser(User user); //根據QueryVo的模糊查詢用戶列表 public List<User> getUsernameByQueryVo(QueryVo vo); //查詢總記錄數 public Integer getCount(); //根據姓名和性別查明用戶 public List<User> getUserBySexAndUserName(User user); //根據多個id查詢用戶 public List<User> getUserByQuery(Query query); //查詢全部用戶信息及訂單信息 public List<User> getUserOrders(); }
一、定義mapper映射文件UserMapper.xml,將UserMapper.xml放在config下mapper目錄下;
二、建立UserMapper接口;
三、修改SqlMapConfig.xml文件加載UserMapper.xml;
注: namespace
mybatis官方推薦使用mapper代理方法開發mapper接口,程序員不用編寫mapper接口實現類,使用mapper代理方法時,輸入參數可使用pojo包裝對象或map對象,保證dao的通用性。
9、SqlMapConfig.xml配置文件:
(一)、SqlMapConfig.xml中配置的內容和順序以下:
properties(屬性)
settings(全局配置參數)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)
(二)、SqlMapConfig.xml能夠引用java屬性文件中的配置信息以下:
在config下定義db.properties(屬性)file文件:鍵值對形式,都必須是String類型!
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 username=root password=123456
MyBatis 將按照下面的順序來加載屬性:
一、 在 properties 元素體內定義的屬性首先被讀取。
二、 而後會讀取properties 元素中resource或 url 加載的屬性,它會覆蓋已讀取的同名屬性。
(三)、typeAliases(類型別名)---也能夠起別名
別名 |
映射的類型 |
_byte |
byte |
_long |
long |
_short |
short |
_int |
int |
_integer |
int |
_double |
double |
_float |
float |
_boolean |
boolean |
string |
String |
byte |
Byte |
long |
Long |
short |
Short |
int |
Integer |
integer |
Integer |
double |
Double |
float |
Float |
boolean |
Boolean |
date |
Date |
decimal |
BigDecimal |
bigdecimal |
BigDecimal |
map |
Map |
(四)、mappers映射器:
一、使用相對於類路徑的資源:
如:<mapper resource="sqlmap/User.xml" />
二、使用mapper接口類路徑
如:<mapper class="cn.mybatis.mapper.UserMapper"/>
注意:此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。
三、註冊指定包下的全部mapper接口
如:<package name="cn.mybatis.mapper"/>
最後:目錄: