提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 談談MyBatis的啟動過程
- 具體的操作過程如下:
- 實現測試類,并測試
- SqlSessionFactory
- SqlSession
- SqlSession有數據安全問題?
- 在MyBatis中,==SqlSession是一個線程不安全的對象==
- 主要原因如下:
- 如何解決這個問題?
- Spring整合MyBatis的解決方案
- 攔截器
- 1 攔截器的定義
- 2 攔截器的應用
- 實際的應用:分頁,SQL檢查。黑白名單。分庫分表等
談談MyBatis的啟動過程
@Test
public void start() throws Exception{// 1. 加載全局配置文件InputStream in = Resources.getResourceAsStream("mybatis-config.xml");// 2.獲取SqlSessionFactory// DefaultSqlSessionFactorySqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);// 3.獲取SqlSession對象 DefaultSqlSession Executor--> SimpleExecutor --> CachingExecutor --> 插件的邏輯植入SqlSession sqlSession = factory.openSession();// 4.通過sqlSession的API接口實現數據庫操作List<User> list = sqlSession.selectList("com.bobo.vip.mapper.UserMapper.selectUserById",2);for (User user : list) {System.out.println(user);}// 關閉會話sqlSession.close();
}
具體的操作過程如下:
- 加載配置文件:MyBatis的配置文件是一個XML文件,包含了數據庫連接信息、映射文件的位置等配置信息。在啟動過程中,MyBatis會讀取并解析這個配置文件。
- 創建SqlSessionFactory對象:SqlSessionFactory是MyBatis的核心對象,用于創建SqlSession對象。在啟動過程中,MyBatis會根據配置文件中的信息,創建一個SqlSessionFactory對象。(工廠模式 ,建造者模式)
- 創建SqlSession對象:SqlSession是MyBatis的會話對象,用于執行數據庫操作。在啟動過程中,MyBatis會根據SqlSessionFactory對象,創建一個SqlSession對象。
- 加載映射文件:映射文件是MyBatis的另一個重要配置,用于定義SQL語句與Java方法之間的映射關系。在啟動過程中,MyBatis會根據配置文件中的信息,加載映射文件。(Mapper文件中的namespace+id)
- 初始化Mapper接口:Mapper接口是用于執行SQL語句的Java接口,在啟動過程中,MyBatis會根據映射文件中的信息,動態生成Mapper接口的實現類。
- 完成啟動:啟動過程完成后,就可以使用SqlSession對象執行數據庫操作了。
實現測試類,并測試
//1.讀取mybatis的核心配置文件(mybatis-config.xml)
//2.通過配置信息獲取一個SqlSessionFactory工廠對象
//3.通過工廠獲取一個SqlSession對象
//4.通過namespace+id找到要執行的sql語句并執行sql語句
//5.輸出結果
也就是
SqlSessionFactory
對象的構建和 SqlSession
對象創建的核心過程。已經具體的數據庫操作的請求是如何實現的。這塊也是面試官比較感興趣的內容。
- SqlSessionFactory:全局配置文件的加載解析和映射文件的加載解析
- SqlSession:相關的核心Executor和攔截器的實例化
- Executor:處理具體的請求涉及到緩存處理。分頁擴展以及Sql解析和參數解析等
https://mybatis.net.cn/getting-started.html
SqlSessionFactory
- SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實例。
- 使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory
被視為一種代碼“壞習慣”。因此 SqlSessionFactory 的最佳作用域是應用作用域。
有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。
SqlSession
- 每個線程都應該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。
- 絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。
- 如果你現在正在使用一種 Web 框架,考慮將 SqlSession 放在一個和 HTTP 請求相似的作用域中。 換句話說,每次收到HTTP 請求,就可以打開一個 SqlSession,返回一個響應后,就關閉它。這個關閉操作很重要,為了確保每次都能執行關閉操作,你應該把這個關閉操作放到 finally 塊中。
下面的示例就是一個確保 SqlSession 關閉的標準模式:
try (SqlSession session = sqlSessionFactory.openSession()) {// 你的應用邏輯代碼
}
在所有代碼中都遵循這種使用模式,可以保證所有數據庫資源都能被正確地關閉。
SqlSession有數據安全問題?
在MyBatis中,SqlSession是一個線程不安全的對象
主要原因如下:
- SqlSession的底層實現是基于JDBC的Connection對象,而Connection對象是非線程安全的,因此SqlSession也是非線程安全的。
- SqlSession中包含了數據庫連接和事務相關的操作,如果多個線程共享同一個SqlSession實例,可能會導致數據的
不一致性
或者事務的混亂
。 - SqlSession中的
緩存機制
也是基于當前線程的,如果多個線程共享同一個SqlSession實例,可能會導致緩存的數據混亂或者不一致。
如何解決這個問題?
- 為了保證數據的安全性和一致性,通常建議在每個線程中使用獨立的SqlSession實例,可以通過工廠模式創建新的SqlSession對象,或者使用MyBatis提供的線程安全的SqlSessionFactory實例來創建SqlSession。
- 另外,可以使用ThreadLocal來保證每個線程中使用的SqlSession對象是唯一的。
Spring整合MyBatis的解決方案
在Spring中,可以通過使用SqlSessionTemplate`來解決SqlSession數據不安全的問題
- SqlSessionTemplate
是MyBatis-Spring提供的一個實現了
SqlSession`接口的類,它會自動管理SqlSession的生命周期,并保證每個線程都有自己的SqlSession實例。 - 使用
SqlSessionTemplate
時,只需要將其配置為Spring的Bean,并注入到需要使用SqlSession的地方即可,Spring會自動為每個線程提供一個獨立的SqlSession實例。
攔截器
1 攔截器的定義
MyBatis 允許你在映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括: https://mybatis.net.cn/configuration.html#plugins
MyBatis 允許你在映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:
- Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler(getParameterObject, setParameters)
- ResultSetHandler(handleResultSets, handleOutputParameters)
- StatementHandler(prepare, parameterize, batch, update, query)
這些類中方法的細節可以通過查看每個方法的簽名來發現,或者直接查看 MyBatis 發行包中的源代碼。 如果你想做的不僅僅是監控方法的調用,那么你最好相當了解要重寫的方法的行為。 因為在試圖修改或重寫已有方法的行為時,很可能會破壞 MyBatis 的核心模塊。 這些都是更底層的類和方法,所以使用插件的時候要特別當心。
2 攔截器的應用
MyBatis攔截器是MyBatis提供的一種插件機制,可以在SQL執行過程中攔截SQL語句并進行相關操作。
攔截器可以用于實現一些通用的功能,如日志記錄、權限校驗、性能監控等。它可以攔截SQL的執行、參數的設置、結果的處理等環節。
要實現一個攔截器,需要實現MyBatis提供的Interceptor接口,并重寫其中的方法。Interceptor接口中定義了3個方法:
- intercept:攔截方法,用于在SQL執行前后進行一些操作。在該方法中可以通過Invocation.proceed()方法調用下一個攔截器或執行目標方法。
- plugin:用于包裝目標對象,返回一個代理對象。可以通過該方法為目標對象生成一個代理對象,以便攔截對目標對象的方法調用。
- setProperties:用于設置攔截器的屬性。可以通過該方法獲取配置文件中的屬性,并進行相應的初始化操作。
??攔截器在MyBatis的配置文件中進行配置,可以通過標簽將攔截器添加到MyBatis的攔截鏈中。使用攔截器可以方便地擴展MyBatis的功能,實現一些通用的需求,并且可以靈活地控制攔截器的順序。
使用的步驟:
先定義
// ExamplePlugin.java
@Intercepts({@Signature(type= Executor.class,method = "update",args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {private Properties properties = new Properties();public Object intercept(Invocation invocation) throws Throwable {// implement pre processing if needObject returnObject = invocation.proceed();// implement post processing if needreturn returnObject;}public void setProperties(Properties properties) {this.properties = properties;}
}
再注冊
<!-- mybatis-config.xml -->
<plugins><plugin interceptor="org.mybatis.example.ExamplePlugin"><property name="someProperty" value="100"/></plugin>
</plugins>
上面的插件將會攔截在 Executor 實例中所有的 “update” 方法調用, 這里的 Executor 是負責執行底層映射語句的內部對象。
實際的應用:分頁,SQL檢查。黑白名單。分庫分表等