Mybatis框架複習大綱面試+提高
Mybatis框架複習大綱【面試+提高】
1.MyBatis面試題匯總
1.1 JDBC編程有哪些不足之處,MyBatis是如何解決這些問題的?
① 資料庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理資料庫鏈接。
② Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
③ 向sql語句傳參數麻煩,因為sql語句的where條件不一定,可能多也可能少,佔位符需要和參數一一對應。
解決: Mybatis自動將java對象映射至sql語句。
④ 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執行結果映射至java對象。
1.2 MyBatis編程步驟是什麼樣的?
① 創建SqlSessionFactory
② 通過SqlSessionFactory創建SqlSession
③ 通過sqlsession執行資料庫操作
④ 調用session.commit()提交事務
⑤ 調用session.close()關閉會話
1.3 MyBatis與Hibernate有哪些不同?
1.Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句。mybatis可以通過XML或註解方式靈活配置要運行的sql語句,並將java對象和sql語句映射生成最終執行的sql,最後將sql執行的結果再映射生成java對象。
2.Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關係數據模型要求不高的軟體開發,例如互聯網軟體、企業運營類軟體等,因為這類軟體需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到資料庫無關性,如果需要實現支持多種資料庫的軟體則需要自定義多套sql映射文件,工作量大。
3.Hibernate對象/關係映射能力強,資料庫無關性好,對於關係模型要求高的軟體(例如需求固定的定製化軟體)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎麼設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。
總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟體架構都是好架構,所以框架只有適合才是最好。
1.4 使用MyBatis的mapper介面調用時有哪些要求?
① Mapper介面方法名和mapper.xml中定義的每個sql的id相同
② Mapper介面方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
③ Mapper介面方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同
④ Mapper.xml文件中的namespace即是mapper介面的類路徑。
1.5 SqlMapConfig.xml中配置有哪些內容?
SqlMapConfig.xml中配置的內容和順序如下:
properties(屬性)
settings(配置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)
1.6簡單的說一下MyBatis的一級緩存和二級緩存?
Mybatis首先去緩存中查詢結果集,如果沒有則查詢資料庫,如果有則從緩存取出返回結果集就不走資料庫。Mybatis內部存儲緩存使用一個HashMap,key為hashCode+sqlId+Sql語句。value為從查詢出來映射生成的java對象
Mybatis的二級緩存即查詢緩存,它的作用域是一個mapper的namespace,即在同一個namespace中查詢sql可以從緩存中獲取數據。二級緩存是可以跨SqlSession的。
1.7Mapper編寫有哪幾種方式?
①介面實現類繼承SqlSessionDaoSupport
使用此種方法需要編寫mapper介面,mapper介面實現類、mapper.xml文件
1).在sqlMapConfig.xml中配置mapper.xml的位置
2).定義mapper介面
3).實現類集成SqlSessionDaoSupport
mapper方法中可以this.getSqlSession()進行數據增刪改查。
4).spring 配置
②使用org.mybatis.spring.mapper.MapperFactoryBean
1).在sqlMapConfig.xml中配置mapper.xml的位置
如果mapper.xml和mappre介面的名稱相同且在同一個目錄,這裡可以不用配置
2).定義mapper介面
注意:
1、mapper.xml中的namespace為mapper介面的地址
2、mapper介面中的方法名和mapper.xml中的定義的statement的id保持一致
3、 Spring中定義
③使用mapper掃描器
1).mapper.xml文件編寫,
注意:
mapper.xml中的namespace為mapper介面的地址
mapper介面中的方法名和mapper.xml中的定義的statement的id保持一致
如果將mapper.xml和mapper介面的名稱保持一致則不用在sqlMapConfig.xml中進行配置
2).定義mapper介面
注意mapper.xml的文件名和mapper的介面名稱保持一致,且放在同一個目錄
3).配置mapper掃描器
4).使用掃描器後從spring容器中獲取mapper的實現對象
掃描器將介面通過代理方法生成實現對象,要spring容器中自動註冊,名稱為mapper 介面的名稱。
2. 建立工程時選擇建立java工程還是web工程?
當建立的工程,需要用到request/response時,需要建立web工程,否則Java工程即可。
3.MyBatis介紹
MyBatis本是apache公司一個名叫iBatis的開源項目,在2010年Apache將其轉移給了Google公司,從apache software foundation 遷移到了google code,並且改名為MyBatis,後來在2013年11月又被Google將其放到了Github上。
MyBatis是一個優秀的持久層框架,它對jdbc操作資料庫的過程進行了封裝,開發者只需要關注SQL本身,而不需要浪費精力去處理,例如:註冊驅動,創建connection,創建statement,手動設置參數,結果集檢索等Jdbc繁雜的過程代碼。
MyBatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java對象和statement中的sql進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射成java對象並返回。
1).和jdbc比較:
mybatis抽離出資料庫的連接,關閉的操作.抽離了sql語句,並且可以自動的進行參數的設置,封裝結果集.
2).和hibernate比較:
- 性能:mybatis較hibernate高
- sql靈活性:mybatis較hibernate高
- 配置文件:mybatis較hibernate多(維護困難)
- 資料庫的無關性:mybatis較hibernate低
4. jdbc編程步驟回顧
註冊資料庫驅動
創建並獲取資料庫鏈接
創建jdbc statement對象
設置sql語句
設置sql語句中的參數(使用preparedStatement)
通過statement執行sql並獲取結果
對sql執行結果進行解析處理, while(resultSet.next)
釋放資源(resultSet,preparedStatement,connection)
5.jdbc問題總結
資料庫連接創建、釋放頻繁造成系統資源浪費,從而影響系統性能。如果使用資料庫連接池可解決此問題。
Sql語句在代碼中硬編碼,造成代碼不易維護,實際應用中sql變化的可能較大,sql變動需要改變java代碼。
使用preparedStatement向佔位符號傳參數存在硬編碼,因為sql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統不易維護。
對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化,系統不易維護,如果能將資料庫記錄封裝成pojo(POJO是指簡單的Java對象,實際就是普通JavaBeans,是為了避免和EJB混淆所創造的簡稱。POJO通指沒有使用Entity Beans的普通java對象,可以把POJO作為支持業務邏輯的協助類。)對象解析比較方便。
6. MyBatis架構
ConfigurationMyBatis所有的配置信息都保存在Configuration對象之中,配置文件中的大部分配置都會存儲到該類中
SqlSession作為MyBatis工作的主要頂層API,表示和資料庫交互時的會話,完成必要資料庫增刪改查功能
ExecutorMyBatis執行器,是MyBatis調度的核心,負責SQL語句的生成和查詢緩存的維護
StatementHandler封裝了JDBC Statement操作,負責對JDBC statement的操作,如設置參數等
ParameterHandler負責對用戶傳遞的參數轉換成JDBC Statement所對應的數據類型
ResultSetHandler負責將JDBC返回的ResultSet結果集對象轉換成List類型的集合
TypeHandler負責java數據類型和jdbc數據類型(也可以說是數據表列類型)之間的映射和轉換
MappedStatementMappedStatement維護一條節點的封裝
SqlSource負責根據用戶傳遞的parameterObject,動態地生成SQL語句,將信息封裝到BoundSql對象中,並返回
BoundSql表示動態生成的SQL語句以及相應的參數信息
7. MyBatis配置(第一種總結方式)
1).SqlMapConfig.xml,此文件作為mybatis的全局(核心)配置文件,配置了mybatis的運行環境等信息。
mapper.xml 文件即sql映射文件,文件中配置了操作資料庫的sql語句。此文件需要在SqlMapConfig.xml中載入。 例如:User.xml
2).通過mybatis環境等配置信息構造SqlSessionFactory即會話工廠 例如:通過流的形式構造SqlSessionFactory會話工廠
①InputStream inputStream = Resources.getResourceAsStream(sqlMapConfig.xml路徑位置);
②SqlSessionFactory sqlSessionFactory = new sqlSessionFactoryBuilder().build(inputStream);
3).由會話工廠創建sqlSession即會話,操作資料庫需要通過sqlSession進行。sqlSession是線程不安全的,每個線程都應該有它獨自的sqlSession,使用完就關閉。
4).mybatis底層自定義了Executor執行器介面操作資料庫,Executor介面有兩個實現,一個是基本執行器、一個是緩存執行器。(Executor才是真正操作資料庫的,不過是底層 所以我們認為是sqlSession在進行操作)
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編程中對結果的解析處理過程。
8.Dao開發(第一種總結方式)
8-1.傳統dao開發
8-1.1.使用上面的UserMapper.xml和SqlMapConfig.xml
8-1.2.創建Dao介面 方法名要與UserMapper.xml中的sql的id一致
8-1.3.創建Dao實現類
8-1.4.對Dao進行junit測試
原始Dao開發中存在以下問題:
Dao方法體存在重複代碼:通過SqlSessionFactory創建SqlSession,調用SqlSession的資料庫操作方法
調用sqlSession的資料庫操作方法需要指定statement的id,這裡存在硬編碼,不便於開發維護。
8-2.Mapper動態代理開發
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的類型相同
8-2.1.SqlMapConfig.xml
8-2.2.UserMapper.java 介面
8-2.3.UserMapper.xml
8-2.4.使用junit進行測試
9.MyBatis配置(第二種總結方式)
全局配置文件:sqlmapconfig.xml
文件中的配置項是有順序的,按照官方圖來配.
configuration
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
* envioronment
* transactionManager
* dataSource
- databaseIdProvider
- mappers
例如:
settings: 全局參數設置
設置延遲載入:
typeAliases:類型別名
mappers:
映射文件
注意點
表示一個佔位符,jdbc中的?通過# 可以將外部傳遞過來映射到sql語句中,可以有效的防止sql注入.
xxx表示一個sql串的拼接,不可以有效防止sql注入.如果是
xxx表示一個sql串的拼接,不可以有效防止sql注入.如果是,輸入的參數類型是簡單類型,那麼$中的xxx必須是value.
parameterType:表示輸入參數的數據類型
resultType:輸出結果的數據類型,如果查詢的是列表,那麼resultType只需要設置列表中的元素的數據類即可.
核心API
執行流程:
載入sqlmapconfig.xml,通過sqlsessionfactorybuilder,構建sqlsesionfactroy對象.由它構建sqlsession提供增刪改查等操作資料庫的方法.
SqlSessionFactoryBuilder
案例
SqlSessionFactory
創建SqlSession的方法:
用openSession方法獲取的SqlSession有以下特點:
- 開啟事務,但是不會自動提交事務
- 將從配置文件中配置的數據源中獲取連接(Connection)
- 事務級別默認使用驅動或數據源的
- 預編譯不會被重用,不會批量更新
列舉3個執行類型參數(ExecutorType):
- ExecutorType.SIMPLE 每次執行都預編譯
- ExecutorType.REUSE 重用預編譯
- ExecutorType.BATCH 批量預編譯
SqlSession
SqlSession執行增刪改查以及事務操作.
10.Dao開發(第二種總結方式)
實現方式:
1. 傳統的Dao建一個dao 建立一個介面,再建實現類.
2. mapper代理的方式,只需要寫介面,不需要寫實現類,實現類由mybatis框架自動創建(官方推薦)
傳統的Dao
sqlsessionfactorybuilder當作一個工具類,一旦使用完畢,就應該銷毀,最佳使用範圍在方法內部.
sqlsessionfactory要單例存在,一旦創建就應當在整個程序運行期使用,沒必要創建一次.使用範圍整個運行期.(整合spring時,可以由spring來管理)
sqlsession是多例的,它線程不安全的,也不能被共享的,使用範圍是在方法的內部.而且,一旦使用完成,必須要關閉,在finally中關閉.
介面:
實現類:
優化:
可以建立一個BaseDaoImpl 繼承sqlsesiondaosupport ,在此進行sqlsessionfactory注入。
mapper動態代理的方式
mapper代理的方式,只需要寫介面,不需要寫實現類,實現類由mybatis框架自動創建.
需要遵守規則:
1. sql的映射文件中的namespace要和Mapper介面中的類路徑(全限定名)一致
2. sql的映射文件中的sql的id要和mapper介面中的方法的名稱一致
3. sql的映射文件中的parameterType要和mapper介面中的方法的參數類型一致
4. sql的映射文件中的resultType要和mapper介面中的方法的返回值數據類型一致
11. #{} 與 ${}區別
#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設置值,自動進行java類型和jdbc類型轉換。#{}可以有效防止sql注入。 #{}可以接收簡單類型值或pojo屬性值。 如果parameterType傳輸單個簡單類型值,#{}括弧中可以是value或其它名稱。
${}表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc類型轉換, ${}可以接收簡單類型值或pojo屬性值,如果parameterType傳輸單個簡單類型值,${}括弧中只能是value。
sql注入案例:"%"#{}"%" 如果#{}傳入的是