MyBatis之八:需要说明的几个java api的生命周期以及封装
學(xué)習(xí)mybatis不得不了解SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession。這里主要是講解它們的生命周期以及一般最佳實(shí)踐。?一般來說對象的生命周期也就是對象創(chuàng)建到銷毀的過程,如果在這個(gè)過程中,如果實(shí)現(xiàn)的代碼質(zhì)量不佳,那么很容易造成程序上的錯(cuò)誤或者效率的降低。
1、SqlSessionFactoryBuilder
SqlSessionFactoryBuilder可以被jvm虛擬機(jī)所實(shí)例化、使用或者銷毀。一旦使用SqlSessionFactoryBuilder對象創(chuàng)建SqlSessionFactory后,SqlSessionFactoryBuilder類就不需要存在了,也就是,不需要保持對象的狀態(tài),可以隨意的由jvm銷毀。因此SqlSessionFactoryBuilder對象的最佳使用范圍是方法內(nèi)部。
? 2、SqlSessionFactory
SqlSessionFactory對象是由SqlSessionFactoryBuilder創(chuàng)建。一旦創(chuàng)建SqlSessionFactory類的實(shí)例,該實(shí)例應(yīng)該在應(yīng)用程序執(zhí)行期間都存在,根本不需要每一次操作數(shù)據(jù)庫時(shí)都創(chuàng)建,所以其最佳實(shí)踐方式就是單例模式,或者使用Spring框架來實(shí)現(xiàn)單例模式對SqlSessionFactory對象進(jìn)行有效管理(后續(xù)會講解)。
? 3、SqlSession
SqlSession對象由SqlSessionFactory類創(chuàng)建,需要注意的是,每個(gè)線程都應(yīng)該有它自己的SqlSession實(shí)例。SqlSession的實(shí)例不能共享,是線程不安全的,其實(shí)我們?nèi)グ强碨qlSession接口定義,可以發(fā)現(xiàn),里面定義了數(shù)據(jù)的增刪改查以及事務(wù)處理以及實(shí)例對象的關(guān)閉。那么很顯然在操作該對象的時(shí)候必須要保持其線程安全,不然在并發(fā)情況下肯定會亂套。或者將SqlSession實(shí)例對象存放在一個(gè)類的靜態(tài)字段甚至是實(shí)例字段中。
4、簡單封裝
由1、2、3得知,SqlSessionFactoryBuilder會被jvm自動銷毀、SqlSessionFactory不需要每次操作數(shù)據(jù)庫都創(chuàng)建、SqlSession必須是線程安全的,那么針對這3點(diǎn),以下做了一個(gè)簡單封裝。
?SyncSqlSessionFactory類主要是獲取SqlSessionFactory單例對象
package com.mybatis.util;import java.io.IOException; import java.io.InputStream;import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class SyncSqlSessionFactory {private static SqlSessionFactory sqlSessionFactory;private SyncSqlSessionFactory() {}synchronized public static SqlSessionFactory getSqlSessionFactory() {try {if (sqlSessionFactory == null) {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}} catch (IOException e) {e.printStackTrace();}return sqlSessionFactory;} }SafeSqlSessionUtil類保證SqlSession線程安全的前提下封裝了事務(wù)的回滾提交操作。
package com.mybatis.util;import org.apache.ibatis.session.SqlSession;public class SafeSqlSessionUtil {private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();public static SqlSession getSqlSession() {SqlSession sqlSession = threadLocal.get();return sqlSession == null ? SyncSqlSessionFactory.getSqlSessionFactory().openSession() : sqlSession;}public static void commit() {if (threadLocal.get() != null) {threadLocal.get().commit();threadLocal.get().close();threadLocal.set(null);}}public static void rollback() {if (threadLocal.get() != null) {threadLocal.get().rollback();threadLocal.get().close();threadLocal.set(null);}} }5、使用示例
try {SqlSession sqlSession = SafeSqlSessionUtil.getSqlSession();//基本操作sqlSession.delete("");sqlSession.update("");sqlSession.select("",null);} catch (Exception e) {SafeSqlSessionUtil.rollback();}finally{SafeSqlSessionUtil.commit();}6、需要說明的地方
synchronized:如果某個(gè)synchronized方法是static的,那么當(dāng)線程訪問該方法時(shí),它鎖的并不是synchronized方法所在的對象,而是synchronized方法所在的類所對應(yīng)的Class對象。Java中,無論一個(gè)類有多少個(gè)對象,這些對象會對應(yīng)唯一一個(gè)Class對象,因此當(dāng)線程分別訪問同一個(gè)類的兩個(gè)對象的兩個(gè)static,synchronized方法時(shí),它們的執(zhí)行順序也是順序的,也就是說一個(gè)線程先去執(zhí)行方法,執(zhí)行完畢后另一個(gè)線程才開始。
ThreadLocal:線程級別的隔離。它通過為每個(gè)線程提供一個(gè)獨(dú)立的變量副本解決了變量并發(fā)訪問的沖突問題。多數(shù)情況下ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問題更簡單,更方便,且結(jié)果程序擁有更高的并發(fā)性。
理解得更加通俗一點(diǎn)就是一個(gè)是鎖機(jī)制進(jìn)行時(shí)間換空間,一個(gè)是存儲拷貝進(jìn)行空間換時(shí)間。
轉(zhuǎn)載于:https://www.cnblogs.com/wucj/p/5162213.html
總結(jié)
以上是生活随笔為你收集整理的MyBatis之八:需要说明的几个java api的生命周期以及封装的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAVA代码走查审查规范
- 下一篇: 复盘二进制的习题(2)