成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

MyBatis的原理

Yu_Huang / 3408人閱讀

摘要:不是線程安全的,所以在使用的時(shí)候一定要保證他是局部變量。他對(duì)應(yīng)的類圖如下有幾種常見的實(shí)現(xiàn)是默認(rèn)的非線程安全的實(shí)現(xiàn)是中對(duì)的線程安全實(shí)現(xiàn),在內(nèi)部是使用的的形式來保證線程安全的是的核心。是線程安全的,可以被多個(gè)或映射器所共享使用。

MyBatis核心類
SqlSessionFactory

每一個(gè)MyBatis應(yīng)用都是以一個(gè)SqlSessionFactory的實(shí)例為核心構(gòu)建的。SqlSessionFactory的核心作用是什么?

從類的名稱上可以看出來,SqlSessionFactory是產(chǎn)生SqlSession的工廠。SqlSessionFactory是通過SqlSessionFactoryBuilder這個(gè)構(gòu)建器來構(gòu)建的。

SqlSessionFactory是一個(gè)接口,其中定義了獲取SqlSession的方法。

public interface SqlSessionFactory {
    //獲取一個(gè)SqlSession
    SqlSession openSession();
    //獲取一個(gè)SqlSession,參數(shù)設(shè)置事務(wù)是否自動(dòng)提交
    SqlSession openSession(boolean var1);
    //通過指定Connection中的參數(shù)獲取
    SqlSession openSession(Connection var1);
    //獲取SqlSession,設(shè)置事務(wù)的隔離級(jí)別,NONE(0),READ_COMMITTED(2),READ_UNCOMMITTED(1),REPEATABLE_READ(4),SERIALIZABLE(8);
    SqlSession openSession(TransactionIsolationLevel var1);
    //獲取SqlSession,同時(shí)制定執(zhí)行的類別,支持三種SIMPLE(這種模式下,將為每個(gè)語句創(chuàng)建一個(gè)PreparedStatement),REUSE(這個(gè)模式下重復(fù)使用preparedStatment),BATCH(批量更新,insert時(shí)候,如果沒有提交,無法獲取自增id);
    SqlSession openSession(ExecutorType var1);
    SqlSession openSession(ExecutorType var1, boolean var2);
    SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
    SqlSession openSession(ExecutorType var1, Connection var2);
    //獲取所有的配置項(xiàng)
    Configuration getConfiguration();
}

SqlSessionFactory包含兩個(gè)實(shí)現(xiàn):DefaultSqlSessionFactorySqlSessionManager
SqlSessionFactory的實(shí)例如何創(chuàng)建呢?
1、通常我們是在只有MyBatis的項(xiàng)目中是使用下面的代碼段來創(chuàng)建的:

String resource = "org/mybatis/example/mybatis-config.xml";
//讀取mybatis配置的問題
InputStream inputStream = Resources.getResourceAsStream(resource);
//通過SqlSessionFactoryBuilder的build方式創(chuàng)建
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

2、在Spring boot和MyBatis結(jié)合的項(xiàng)目中我會(huì)使用下面的代碼段來創(chuàng)建:

MyBatis-Spring-Boot-Starter依賴將會(huì)提供如下

自動(dòng)檢測(cè)現(xiàn)有的DataSource

將創(chuàng)建并注冊(cè)SqlSessionFactory的實(shí)例,該實(shí)例使用SqlSessionFactoryBean將該DataSource作為輸入進(jìn)行傳遞

將創(chuàng)建并注冊(cè)從SqlSessionFactory中獲取的SqlSessionTemplate的實(shí)例。

自動(dòng)掃描您的mappers,將它們鏈接到SqlSessionTemplate并將其注冊(cè)到Spring上下文,以便將它們注入到您的bean中。

就是說,使用了該Starter之后,只需要定義一個(gè)DataSource即可(application.properties中可配置),它會(huì)自動(dòng)創(chuàng)建使用該DataSource的SqlSessionFactory Bean以及SqlSessionTemplate。會(huì)自動(dòng)掃描你的Mappers,連接到SqlSessionTemplate,并注冊(cè)到Spring上下文中.

@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("druidDataSource") DataSource druidDataSource) throws Exception {
    //先創(chuàng)建一個(gè)SqlSessionFactoryBean
    SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
    //在這個(gè)bean里設(shè)置需要的參數(shù)
    fb.setDataSource(this.dynamicDataSource(druidDataSource));
    fb.setTypeAliasesPackage(env.getProperty("mybatis.type-aliases-package"));
    fb.setTypeHandlersPackage(env.getProperty("mybatis.type-handlers-package"));
    fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));
    //通過這個(gè)方法獲取一個(gè)SqlSessionFactory
    return fb.getObject();
}

在代碼里一直向下查找的時(shí)候就會(huì)發(fā)現(xiàn):這個(gè)過程其實(shí)和上面的過程一樣。
SqlSessionFactoryBean會(huì)將一系列的屬性封裝成一個(gè)Configuration對(duì)象,然后調(diào)用
this.sqlSessionFactoryBuilder.build(configuration) 來創(chuàng)建。而在sqlSessionFactoryBuilder里主要就是解析資源的內(nèi)容,然后進(jìn)行創(chuàng)建。

在這里有分別使用了兩個(gè)設(shè)計(jì)模式:

工廠模式

SqlSessionFactory就是一個(gè)工廠模式——簡單工廠模式的變形實(shí)現(xiàn)。
通過SqlSessionFactory中重載的不同openSession()方法來獲取不同類型的實(shí)例。

建造者模式(build模式)

SqlSessionFactoryBuilder創(chuàng)建SqlSessionFactory就是建造者模式的實(shí)現(xiàn)。在創(chuàng)建的過程中需要解析很多的文件,生成對(duì)象,進(jìn)行緩存等操作,所以一個(gè)方法是很難直接寫完,所以其中應(yīng)用了大量的build模式:

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
    XMLConfigBuilder xmlConfigBuilder = null;
    Configuration configuration;
    if (this.configuration != null) {
       ......
    } else if (this.configLocation != null) {
        xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
        configuration = xmlConfigBuilder.getConfiguration();
    } else {
        ......
    }
    ......

    if (xmlConfigBuilder != null) {
        try {
            //builder解析
            xmlConfigBuilder.parse();
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Parsed configuration file: "" + this.configLocation + """);
            }
        } catch (Exception var22) {
            throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var22);
        } finally {
            ErrorContext.instance().reset();
        }
    }
    ......
    if (!ObjectUtils.isEmpty(this.mapperLocations)) {
        Resource[] var29 = this.mapperLocations;
        var27 = var29.length;

        for(var5 = 0; var5 < var27; ++var5) {
            Resource mapperLocation = var29[var5];
            if (mapperLocation != null) {
                try {
                    //Mapper文件build
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments());
                    xmlMapperBuilder.parse();
                } catch (Exception var20) {
                    
                } finally {
                    //單例模式
                    ErrorContext.instance().reset();
                }
            }
        }
    } 
    //build一個(gè)對(duì)象返回
    return this.sqlSessionFactoryBuilder.build(configuration);
}
SqlSession

SqlSessionFactory創(chuàng)建完成之后,就可以通過SqlSessionFactory對(duì)象來獲取一個(gè)SqlSession實(shí)例.SqlSession是一次與數(shù)據(jù)庫的會(huì)話.在他的接口中定義了一些列的CRUD和事務(wù)的操作接口。SqlSession是暴露給用戶使用的API,一個(gè)SqlSession對(duì)應(yīng)著一次數(shù)據(jù)庫會(huì)話。SqlSession不是線程安全的,所以在使用的時(shí)候一定要保證他是局部變量。
他對(duì)應(yīng)的類圖如下:

SqlSession有幾種常見的實(shí)現(xiàn):DefaultSqkSession是默認(rèn)的非線程安全的實(shí)現(xiàn),SqlSessionManager是Mybatis中對(duì)SqlSession的線程安全實(shí)現(xiàn),在內(nèi)部是使用的private ThreadLocal localSqlSession = new ThreadLocal();的形式來保證線程安全的,SqlSessionTemplate是MyBatis-Spring 的核心。作為 SqlSession 的一個(gè)實(shí)現(xiàn),這意味著可以使用它無縫代替你代碼中已經(jīng)在使用的 SqlSession。SqlSessionTemplate 是線程安全的,可以被多個(gè) DAO 或映射器所共享使用。

因?yàn)?b>SqlSessionTemplate是線程安全的,所以當(dāng)SqlSessionTemplate是單例的時(shí)候,多線程調(diào)用SqlSessionTemplate仍然使用的是同一個(gè)SqlSession,接下來看一下SqlSessionTemplate是如何保證線程安全的呢?

首先我們看一下SqlSessionTemplate的創(chuàng)建過程:

/**
 * 構(gòu)造函數(shù)1,需要傳入?yún)?shù)SqlSessionFactory
 */
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
}

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
    this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
}

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    Assert.notNull(sqlSessionFactory, "Property "sqlSessionFactory" is required");
    Assert.notNull(executorType, "Property "executorType" is required");
    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    //創(chuàng)建代理類的實(shí)例,該代理類實(shí)現(xiàn)了SqlSession接口,這里使用的是基于JDK的動(dòng)態(tài)代理,SqlSessionInterceptor也是實(shí)現(xiàn)了InvocationHandler接口,最后代理對(duì)象的操作都會(huì)經(jīng)過invoke執(zhí)行
    //class SqlSessionInterceptor implements InvocationHandler
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}

invoke的實(shí)現(xiàn)是實(shí)現(xiàn)線程安全的核心:

private class SqlSessionInterceptor implements InvocationHandler {
    private SqlSessionInterceptor() {
    }
  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     //獲取真實(shí)的SqlSession,這個(gè)是真實(shí)使用的,是MyBatis生成的DefaultSqlSession,獲取是線程安全實(shí)現(xiàn)的核心
        SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);

        Object unwrapped;
        try {
            //執(zhí)行操作
            Object result = method.invoke(sqlSession, args);
            //如果不是事務(wù)類型的,那么設(shè)置為自動(dòng)提交
            if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                sqlSession.commit(true);
            }
            //執(zhí)行結(jié)果包裝
            unwrapped = result;
        } catch (Throwable var11) {
            unwrapped = ExceptionUtil.unwrapThrowable(var11);
            if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                sqlSession = null;
                Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
                if (translated != null) {
                    unwrapped = translated;
                }
            }

            throw (Throwable)unwrapped;
        } finally {
            if (sqlSession != null) {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }

        }
        //返回執(zhí)行結(jié)果
        return unwrapped;
    }
}

接著看getSqlSession()的代碼:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    Assert.notNull(sessionFactory, "No SqlSessionFactory specified");
    Assert.notNull(executorType, "No ExecutorType specified");
    //SqlSessionHolder是對(duì)SqlSession的一個(gè)功能包裝,TransactionSynchronizationManager是一個(gè)事務(wù)同步管理器,維護(hù)當(dāng)前線程事務(wù)資源,信息以及TxSync集合,getResource會(huì)從 ThreadLocal> resources 中獲取當(dāng)前線程SqlSessionHolder實(shí)例
    SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
        return session;
    } else {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Creating a new SqlSession");
        }
        //如果沒有獲取成功,那么開啟一個(gè)SqlSession
        session = sessionFactory.openSession(executorType);
        //注冊(cè)SessionHolder
        registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
        return session;
    }
}

registerSessionHolder()實(shí)現(xiàn)?

好難啊~~~~~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74713.html

相關(guān)文章

  • 帶你深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)(PDF實(shí)戰(zhàn)實(shí)踐)

    摘要:目錄其中每個(gè)章節(jié)知識(shí)點(diǎn)都是相關(guān)連由淺入深的一步步全面分析了技術(shù)原理以及實(shí)戰(zhàn)由于文案較長想深入學(xué)習(xí)以及對(duì)于該文檔感興趣的朋友們可以加群免費(fèi)獲取。這些場景在大量的編碼中使用,具備較強(qiáng)的實(shí)用價(jià)值,這些內(nèi)容都是通過實(shí)戰(zhàn)得來的,供讀者們參考。 前言系統(tǒng)掌握MyBatis編程技巧已經(jīng)成了用Java構(gòu)建移動(dòng)互聯(lián)網(wǎng)網(wǎng)站的必要條件 本文主要講解了Mybatis的應(yīng)用,解析了其原理,從而形成一個(gè)完整的知識(shí)...

    MoAir 評(píng)論0 收藏0
  • Mybatis常見面試題

    摘要:執(zhí)行沒有,批處理不支持,將所有都添加到批處理中,等待統(tǒng)一執(zhí)行,它緩存了多個(gè)對(duì)象,每個(gè)對(duì)象都是完畢后,等待逐一執(zhí)行批處理。 Mybatis常見面試題 #{}和${}的區(qū)別是什么? #{}和${}的區(qū)別是什么? 在Mybatis中,有兩種占位符 #{}解析傳遞進(jìn)來的參數(shù)數(shù)據(jù) ${}對(duì)傳遞進(jìn)來的參數(shù)原樣拼接在SQL中 #{}是預(yù)編譯處理,${}是字符串替換。 使用#{}可以有效的防止...

    liuchengxu 評(píng)論0 收藏0
  • 面試官都會(huì)問Mybatis面試題,你會(huì)這樣回答嗎?

    摘要:最終能和面試官聊的開心愉快投緣的叫面霸。能夠與很好的集成提供映射標(biāo)簽,支持對(duì)象與數(shù)據(jù)庫的字段關(guān)系映射提供對(duì)象關(guān)系映射標(biāo)簽,支持對(duì)象關(guān)系組件維護(hù)。使用可以有效的防止注入,提高系統(tǒng)安全性。 showImg(https://segmentfault.com/img/bVbsSlt?w=358&h=269); 一、概述 面試,難還是不難?取決于面試者的底蘊(yùn)(氣場+技能)、心態(tài)和認(rèn)知及溝通技巧。...

    seanHai 評(píng)論0 收藏0
  • 手撕面試官系列(二):開源框架面試題Spring+SpringMVC+MyBatis

    摘要:跳槽時(shí)時(shí)刻刻都在發(fā)生,但是我建議大家跳槽之前,先想清楚為什么要跳槽。切不可跟風(fēng),看到同事一個(gè)個(gè)都走了,自己也盲目的開始面試起來期間也沒有準(zhǔn)備充分,到底是因?yàn)榧夹g(shù)原因影響自己的發(fā)展,偏移自己規(guī)劃的軌跡,還是錢給少了,不受重視。 跳槽時(shí)時(shí)刻刻都在發(fā)生,但是我建議大家跳槽之前,先想清楚為什么要跳槽。切不可跟風(fēng),看到同事一個(gè)個(gè)都走了,自己也盲目的開始面試起來(期間也沒有準(zhǔn)備充分),到底是因?yàn)榧?..

    Flink_China 評(píng)論0 收藏0
  • 教你手寫Mybatis框架

    摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫,讓大家對(duì)的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類,用于解析配置文件加載相關(guān)環(huán)境。配置模塊這里的對(duì)框架的配置使用了簡單的,主要原因還是簡單易懂然后節(jié)省時(shí)間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫mybatis,讓大家對(duì)mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...

    antyiwei 評(píng)論0 收藏0
  • Java深入-框架技巧

    摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進(jìn)階面試問題列表 -...

    chengtao1633 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<