mybatis的介紹
Mybatis是一個封裝來jdbc的持久層框架,它和Hibernate都屬於ORM框架,但是具體來講,Hibernate是一個完全的ORM框架,而Mybatis是一個不完全的ORM框架。
Mybatis讓程序員只關注sql本身,而不需要再去關注如連接的創建、statement的創建等操作(類似於把需要重複使用的方法包裝起來)。
Mybatis會將輸入參數、輸出結果進行映射。
分析jdbc的問題
原生態的jdbc代碼
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1、加載數據庫驅動
Class.forName("com.mysql.jdbc.Driver");
//2、通過驅動管理類獲取數據庫鏈接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "admiin");
//3、定義sql語句 ?表示佔位符
String sql = "select * from user where username = ?";
//4、獲取預處理statement
preparedStatement = connection.prepareStatement(sql);
//5、設置參數,第一個參數爲sql語句中參數的序號(從1開始),第二個參數爲設置的參數值
preparedStatement.setString(1, "王五");
//6、向數據庫發出sql執行查詢,查詢出結果集
resultSet = preparedStatement.executeQuery();
//7、遍歷查詢結果集
while(resultSet.next()){
User user
System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//8、釋放資源
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.配置文件(全局配置文件):
在執行statement時存在硬編碼
3.配置文件(映射文件)
頻繁的開啓和關閉數據庫連接,會造成數據庫性能下降。
數據庫連接池(全局配置文件)
Mybatis的框架原理
參考畫圖.xlsx
入門程序
從需求入手:
對訂單商品案例中的用戶表進行增刪改查操作
- 根據用戶ID查詢用戶信息
- 根據用戶名稱模糊查詢用戶列表
- 添加用戶
- 刪除用戶(練習)
- 修改用戶(練習)
環境配置準備
Jdk:1.8
Idea:Rapideclipse
Mybatis:3.5.2
數據庫:MySQL
下載mybatis(去maven裏查找然後注入依賴)
- 數據庫腳本初始化
- 數據庫腳本
導入包:
1.執行sql_table.sql腳本,創建數據庫表;
2.執行sql_data.sql初始化測試數據。
工程搭建
- 注入Mybatis的核心包和依賴包
- 注入MySQl的驅動包
- Junit(非必須)
代碼實現
創建pojo類(例如對象的屬性,getset方法等等)
創建全局配置文件
在config目錄下,創建mybatis-config.xml文件。
需求開發
- 根據用戶ID查詢用戶信息
映射文件:
在config目錄下,創建UserMapper.xml(這種命名規範是由ibatis遺留下來)
在全局配置文件中加載映射文件
測試代碼
記得更改圖中的配置文件,那是先前的~
根據用戶名稱模糊查詢用戶列表
- 射文件
測試代碼
2.添加用戶
映射文件
測試代碼
主鍵返回之自增主鍵
主鍵返回值UUID
UUID函數是mysql的函數
主鍵返回值序列
序列也就是sequence,它是Oracle的主鍵生成策略
小結
認識一些比較特殊的符號(及語法使用差不多)
1.#{}和${}
#{}表示佔位符?,#{}接收簡單類型的參數時,裏面的名稱可以任意
${}表示拼接符,${}接收簡單類型的參數時,裏面的名稱必須是value
${}裏面的值會原樣輸出,不加解析(如果該參數值是字符串,有不會添加引號)
${}存在sql注入的風險,但是有些場景下必須使用,比如排序後面會動態傳入排序的列名
2.parameterType和resultType
parameterType指定輸入參數的java類型,parameterType只有一個,也就是說入參只有一個。
resultType指定輸出結果的java類型(是單條記錄的java類型)
3.selectOne和selectList
selectOne查詢單個對象
selectList查詢集合對象
mybatis開發dao的方式
需求:
- 根據用戶ID查詢用戶信息
- 根據用戶名稱模糊查詢用戶列表
- 添加用戶
- 原始dao的開發方式
即開發dao接口和dao實現類
1.Dao接口
2.Dao實現類
SqlSessionFactory,它的生命週期,應該是應用範圍,全局範圍只有一個工廠,使用單例模式來實現這個功能。與spring集成之後,由spring來對其進行單例管理。
SqlSession,它內部含有一塊數據區域,存在線程不安全的問題,所以應該將sqlsession聲明到方法內部。
public class UserDaoImpl implements UserDao {
// 依賴注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
// 創建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 調用SqlSession的增刪改查方法
// 第一個參數:表示statement的唯一標示
User user = sqlSession.selectOne("test.findUserById", id);
System.out.println(user);
// 關閉資源
sqlSession.close();
return sqlSession.selectOne("test.findUserById", 1);
}
@Override
public List<User> findUsersByName(String name) {
// 創建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 調用SqlSession的增刪改查方法
// 第一個參數:表示statement的唯一標示
List<User> list = sqlSession.selectOne("test.findUsersByName", name);
System.out.println(list);
// 關閉資源
sqlSession.close();
return list;
}
@Override
public void insertUser(User user) {
// 創建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 調用SqlSession的增刪改查方法
// 第一個參數:表示statement的唯一標示
sqlSession.insert("test.insertUser", user);
System.out.println(user.getId());
// 提交事務
sqlSession.commit();
// 關閉資源
sqlSession.close();
}
}
測試代碼
問題思考?
- 以上代碼有大量的重複的模板代碼
- 存在硬編碼
- 想辦法改善它
Mapper代理的開發方式
即開發mapper接口(相當於dao接口)
Mapper代理使用的是jdk的代理策略。
Mapper代理的開發規範
- mapper接口的全限定名要和mapper映射文件的namespace值一致。
- mapper接口的方法名稱要和mapper映射文件的statement的id一致。
- mapper接口的方法參數類型要和mapper映射文件的statement的parameterType的值一致,而且它的參數是一個。
- mapper接口的方法返回值類型要和mapper映射文件的statement的resultType的值一致。
- mapper接口
mapper映射文件
在config下創建mapper目錄然後創建UserMapper.xml(這是mybatis的命名規範,當然,也不是必須是這個名稱)
sqlSession內部的數據區域本身就是一級緩存,是通過map來存儲的。
- 加載映射文件
2.測試代碼
- 全局配置文件
- 概覽
SqlMapConfig.xml的配置內容和順序如下(順序不能亂):
Properties(屬性)
Settings(全局參數設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境信息集合)
environment(單個環境信息)
transactionManager(事物)
dataSource(數據源)
mappers(映射器)
-
- 常用配置
- Properties
- 常用配置
jdbc.properties
SqlMapConfig.xml
加載的順序
- 先加載properties中property標籤聲明的屬性
- 再加載properties標籤引入的java配置文件中的屬性
- parameterType的值會和properties的屬性值發生衝突。
- settings
mybatis全局配置參數,全局參數將會影響mybatis的運行行爲。
詳細參見“mybatis學習資料/mybatis-settings.xlsx”文件
2.typeAliases
對po類進行別名的定義
- mybatis支持的別名
別名 |
映射的類型 |
_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 |
自定義別名
1.Mappers
<mapper resource=’’/>
使用相對於類路徑的資源
如:<mapper resource="sqlmap/User.xml" />
2.<mapper url=’’/>
使用完全限定路徑
如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />
3.<mapper class=’’/>
使用mapper接口的全限定名
如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
注意:此種方法要求mapper接口和mapper映射文件要名稱相同,且放到同一個目錄下;
- <package name=’’/>(推薦)
註冊指定包下的所有映射文件
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此種方法要求mapper接口和mapper映射文件要名稱相同,且放到同一個目錄下;
映射文件:
1.輸入映射
2.簡單類型
根據用戶ID查詢用戶信息的映射文件
Pojo類型
添加用戶的映射文件
包裝pojo類型
需求:
綜合查詢時,可能會根據用戶信息、商品信息、訂單信息等作爲條件進行查詢,用戶信息中的查詢條件由:用戶的名稱和性別進行查詢
1建包裝pojo
2.映射文件
3.Mapper接口
4.測試代碼
Map結合使用
同傳遞POJO對象一樣,map的key相當於pojo的屬性。
1.映射文件
<!-- 傳遞hashmap綜合查詢用戶信息 -->
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
</select>
2.測試代碼
Public void testFindUserByHashmap()throws Exception{
//獲取session
SqlSession session = sqlSessionFactory.openSession();
//獲限mapper接口實例
UserMapper userMapper = session.getMapper(UserMapper.class);
//構造查詢條件Hashmap對象
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("username", "管理員");
//傳遞Hashmap對象查詢用戶列表
List<User>list = userMapper.findUserByHashmap(map);
//關閉session
session.close();
}
異常測試:
傳遞的map中的key和sql中解析的key不一致。
測試結果沒有報錯,只是通過key獲取值爲空。
輸出映射
- resultType
- 使用要求
使用resultType進行結果映射時,需要查詢出的列名和映射的對象的屬性名一致,才能映射成功。
如果查詢的列名和對象的屬性名全部不一致,那麼映射的對象爲空。
如果查詢的列名和對象的屬性名有一個一致,那麼映射的對象不爲空,但是隻有映射正確那一個屬性纔有值。
如果查詢的sql的列名有別名,那麼這個別名就是和屬性映射的列名。
1.簡單類型
注意,對簡單類型的結果映射也是有要求的,查詢的列必須是一列,才能映射爲簡單類型。
2.需求
綜合查詢時,需要根據綜合查詢的添加查詢用戶的總數
3.映射文件
4.Mapper接口
5.測試代碼
Pojo對象和pojo列表
參考入門程序之根據用戶ID查詢用戶信息和根據用戶名稱模糊查詢用戶列
resultMap
使用要求:
使用resultMap進行結果映射時,不需要查詢的列名和映射的屬性名必須一致。但是需要聲明一個resultMap,來對列名和屬性名進行映射。
需求:
對以下sql查詢的結果集進行對象映射
Select id id_,username username_,sex sex_ from user where id = 1;
1.映射文件
2.Mapper接口
3.測試代碼
動態sql
在mybatis中,它提供了一些動態sql標籤,可以讓程序員更快的進行mybatis的開發,這些動態sql可以通過sql的可重用性。。
常用的動態sql標籤:if標籤、where標籤、sql片段、foreach標籤
- If標籤/where標籤
需求:
綜合查詢時,查詢條件由用戶來輸入,用戶名稱可以爲空,需要滿足這種情況下的sql編寫。
映射文件
測試代碼
Sql片段
Sql片段可以讓代碼有更高的可重用性
Sql片段需要先定義後使用
Foreach標籤
可以循環傳入參數值
需求:
綜合查詢時,會根據用戶ID集合進行查詢
SELECT * FROM USER WHERE id IN (1,2,10)
1.修改包裝pojo
2.映射文件
3.測試代碼
mybatis與hibernate的區別及各自應用場景
Mybatis技術特點:
優點:通過直接編寫SQL語句,可以直接對SQL進行性能的優化;
學習門檻低,學習成本低。只要有SQL基礎,就可以學習mybatis,而且很容易上手;
由於直接編寫SQL語句,所以靈活多變,代碼維護性更好。
缺點:不能支持數據庫無關性,即數據庫發生變更,要寫多套代碼進行支持,移植性不好。
Hibernate技術特點:
優點:標準的orm框架,程序員不需要編寫SQL語句。
具有良好的數據庫無關性,即數據庫發生變化的話,代碼無需再次編寫。
學習要求:學習門檻較高,需要對數據關係模型有良好的基礎,而且在設置OR映射的時候,需要考慮好性能和對象模型的權衡。
缺點:程序員不能自主的去進行SQL性能優化。
Mybatis應用場景:
需求多變的互聯網項目,例如電商項目。
Hibernate應用場景:
需求明確、業務固定的項目,例如OA項目、ERP項目等。
以上總結尚未完善好,有基礎的同學應該都大概懂一些!