<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試:Mybatis事務(wù)請(qǐng)講解一下?

          共 6825字,需瀏覽 14分鐘

           ·

          2020-07-28 12:10

          點(diǎn)擊上方“JAVA”,星標(biāo)公眾號(hào)
          重磅干貨,第一時(shí)間送達(dá)

          1.說(shuō)到數(shù)據(jù)庫(kù)事務(wù),人們腦海里自然不自然的就會(huì)浮現(xiàn)出事務(wù)的四大特性、四大隔離級(jí)別、七大傳播特性。四大還好說(shuō),問(wèn)題是七大傳播特性是哪兒來(lái)的?是Spring在當(dāng)前線程內(nèi),處理多個(gè)數(shù)據(jù)庫(kù)操作方法事務(wù)時(shí)所做的一種事務(wù)應(yīng)用策略。事務(wù)本身并不存在什么傳播特性,不要混淆事務(wù)本身和Spring的事務(wù)應(yīng)用策略。(當(dāng)然,找工作面試時(shí),還是可以巧妙的描述傳播特性的)

          2.一說(shuō)到事務(wù),人們可能又會(huì)想起create、begin、commit、rollback、close、suspend??蓪?shí)際上,只有commit、rollback是實(shí)際存在的,剩下的create、begin、close、suspend都是虛幻的,是業(yè)務(wù)層或數(shù)據(jù)庫(kù)底層應(yīng)用語(yǔ)意,而非JDBC事務(wù)的真實(shí)命令。

          create(事務(wù)創(chuàng)建):不存在。
          begin(事務(wù)開(kāi)始):姑且認(rèn)為存在于DB的命令行中,比如Mysql的start transaction命令,以及其他數(shù)據(jù)庫(kù)中的begin transaction命令。JDBC中不存在。
          close(事務(wù)關(guān)閉):不存在。應(yīng)用程序接口中的close()方法,是為了把connection放回?cái)?shù)據(jù)庫(kù)連接池中,供下一次使用,與事務(wù)毫無(wú)關(guān)系。
          suspend(事務(wù)掛起):不存在。Spring中事務(wù)掛起的含義是,需要新事務(wù)時(shí),將現(xiàn)有的connection1保存起來(lái)(它還有尚未提交的事務(wù)),然后創(chuàng)建connection2,connection2提交、回滾、關(guān)閉完畢后,再把connection1取出來(lái),完成提交、回滾、關(guān)閉等動(dòng)作,保存connection1的動(dòng)作稱之為事務(wù)掛起。在JDBC中,是根本不存在事務(wù)掛起的說(shuō)法的,也不存在這樣的接口方法。

          因此,記住事務(wù)的三個(gè)真實(shí)存在的方法,不要被各種事務(wù)狀態(tài)名詞所迷惑,它們分別是:conn.setAutoCommit()、conn.commit()、conn.rollback()。
          conn.close()含義為關(guān)閉一個(gè)數(shù)據(jù)庫(kù)連接,這已經(jīng)不再是事務(wù)方法了。




          1. Mybaits中的事務(wù)接口Transaction

          public?interface?Transaction?{
          ????Connection?getConnection()?throws?SQLException;
          ????void?commit()?throws?SQLException;
          ????void?rollback()?throws?SQLException;
          ????void?close()?throws?SQLException;
          }

          有了文章開(kāi)頭的分析,當(dāng)你再次看到close()方法時(shí),千萬(wàn)別再認(rèn)為是關(guān)閉一個(gè)事務(wù)了,而是關(guān)閉一個(gè)conn連接,或者是把conn連接放回連接池內(nèi)。

          事務(wù)類層次結(jié)構(gòu)圖:

          ? ? ? ? ? ? ? ? ? ? ? ? (Made In Intellij Idea IDE)

          JdbcTransaction:?jiǎn)为?dú)使用Mybatis時(shí),默認(rèn)的事務(wù)管理實(shí)現(xiàn)類,就和它的名字一樣,它就是我們常說(shuō)的JDBC事務(wù)的極簡(jiǎn)封裝,和編程使用mysql-connector-java-5.1.38-bin.jar事務(wù)驅(qū)動(dòng)沒(méi)啥差別。其極簡(jiǎn)封裝,僅是讓connection支持連接池而已。

          ManagedTransaction:含義為托管事務(wù),空殼事務(wù)管理器,皮包公司。僅是提醒用戶,在其它環(huán)境中應(yīng)用時(shí),把事務(wù)托管給其它框架,比如托管給Spring,讓Spring去管理事務(wù)。

          org.apache.ibatis.transaction.jdbc.JdbcTransaction.java部分源碼。

          @Override
          ??public?void?close()?throws?SQLException?{
          ????if?(connection?!=?null)?{
          ??????resetAutoCommit();
          ??????if?(log.isDebugEnabled())?{
          ????????log.debug("Closing?JDBC?Connection?["?+?connection?+?"]");
          ??????}
          ??????connection.close();
          ????}
          ??}

          面對(duì)上面這段代碼,我們不禁好奇,connection.close()之前,居然調(diào)用了一個(gè)resetAutoCommit(),含義為重置autoCommit屬性值。connection.close()含義為銷毀conn,既然要銷毀conn,為何還多此一舉的調(diào)用一個(gè)resetAutoCommit()呢?消失之前多喝口水,真的沒(méi)有必要。

          其實(shí),原因是這樣的,connection.close()不意味著真的要銷毀conn,而是要把conn放回連接池,供下一次使用,既然還要使用,自然就需要重置AutoCommit屬性了。通過(guò)生成connection代理類,來(lái)實(shí)現(xiàn)重回連接池的功能。如果connection是普通的Connection實(shí)例,那么代碼也是沒(méi)有問(wèn)題的,雙重支持。


          2. 事務(wù)工廠TransactionFactory

          顧名思義,一個(gè)生產(chǎn)JdbcTransaction實(shí)例,一個(gè)生產(chǎn)ManagedTransaction實(shí)例。兩個(gè)毫無(wú)實(shí)際意義的工廠類,除了new之外,沒(méi)有其他代碼。

          type="JDBC"?/>

          mybatis-config.xml配置文件內(nèi),可配置事務(wù)管理類型。


          3.?Transaction的用法

          無(wú)論是SqlSession,還是Executor,它們的事務(wù)方法,最終都指向了Transaction的事務(wù)方法,即都是由Transaction來(lái)完成事務(wù)提交、回滾的。

          配一個(gè)簡(jiǎn)單的時(shí)序圖。

          ? ? ? ? ? ? ? ? ? ??(Made In Visual Paradigm)

          代碼樣例:

          public?static?void?main(String[]?args)?{
          SqlSession?sqlSession?=?MybatisSqlSessionFactory.openSession();
          try?{
          StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);

          Student?student?=?new?Student();
          student.setName("yy");
          student.setEmail("[email protected]");
          student.setDob(new?Date());
          student.setPhone(new?PhoneNumber("123-2568-8947"));

          studentMapper.insertStudent(student);
          sqlSession.commit();
          }?catch?(Exception?e)?{
          sqlSession.rollback();
          }?finally?{
          sqlSession.close();
          }
          }

          注:Executor在執(zhí)行insertStudent(student)方法時(shí),與事務(wù)的提交、回滾、關(guān)閉毫無(wú)瓜葛(方法內(nèi)部不會(huì)提交、回滾事務(wù)),需要像上面的代碼一樣,手動(dòng)顯示調(diào)用commit()、rollback()、close()等方法。

          因此,后續(xù)在分析到類似insert()、update()等方法內(nèi)部時(shí),需要忘記事務(wù)的存在,不要試圖在insert()等方法內(nèi)部尋找有關(guān)事務(wù)的任何方法。


          4. 你可能關(guān)心的有關(guān)事務(wù)的幾種特殊場(chǎng)景表現(xiàn)(重要)


          1. 一個(gè)conn生命周期內(nèi),可以存在無(wú)數(shù)多個(gè)事務(wù)。

          ????????????//?執(zhí)行了connection.setAutoCommit(false),并返回
          ????????????SqlSession?sqlSession?=?MybatisSqlSessionFactory.openSession();
          try?{
          StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);

          Student?student?=?new?Student();
          student.setName("yy");
          student.setEmail("[email protected]");
          student.setDob(new?Date());
          student.setPhone(new?PhoneNumber("123-2568-8947"));

          studentMapper.insertStudent(student);
          //?提交
          sqlSession.commit();

          studentMapper.insertStudent(student);
          //?多次提交
          sqlSession.commit();
          }?catch?(Exception?e)?{
          ????????//?回滾,只能回滾當(dāng)前未提交的事務(wù)
          sqlSession.rollback();
          }?finally?{
          sqlSession.close();
          }

          對(duì)于JDBC來(lái)說(shuō),autoCommit=false時(shí),是自動(dòng)開(kāi)啟事務(wù)的,執(zhí)行commit()后,該事務(wù)結(jié)束。以上代碼正常情況下,開(kāi)啟了2個(gè)事務(wù),向數(shù)據(jù)庫(kù)插入了2條數(shù)據(jù)。JDBC中不存在Hibernate中的session的概念,在JDBC中,insert了幾次,數(shù)據(jù)庫(kù)就會(huì)有幾條記錄,切勿混淆。而rollback(),只能回滾當(dāng)前未提交的事務(wù)。


          2. autoCommit=false,沒(méi)有執(zhí)行commit(),僅執(zhí)行close(),會(huì)發(fā)生什么?

          try?{
          ????studentMapper.insertStudent(student);
          }?finally?{
          ????sqlSession.close();
          }

          就像上面這樣的代碼,沒(méi)有commit(),固執(zhí)的程序員總是好奇這樣的特例。

          insert后,close之前,如果數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別是read uncommitted,那么,我們可以在數(shù)據(jù)庫(kù)中查詢到該條記錄。

          接著執(zhí)行sqlSession.close()時(shí),經(jīng)過(guò)SqlSession的判斷,決定執(zhí)行rollback()操作,于是,事務(wù)回滾,數(shù)據(jù)庫(kù)記錄消失。

          下面,我們看看org.apache.ibatis.session.defaults.DefaultSqlSession.java中的close()方法源碼。

          ??@Override
          ??public?void?close()?{
          ????try?{
          ??????executor.close(isCommitOrRollbackRequired(false));
          ??????dirty?=?false;
          ????}?finally?{
          ??????ErrorContext.instance().reset();
          ????}
          ??}

          事務(wù)是否回滾,依靠isCommitOrRollbackRequired(false)方法來(lái)判斷。

          ??private?boolean?isCommitOrRollbackRequired(boolean?force)?{
          ????return?(!autoCommit?&&?dirty)?||?force;
          ??}

          在上面的條件判斷中,!autoCommit=true(取反當(dāng)然是true了),force=false,最終是否回滾事務(wù),只有dirty參數(shù)了,dirty含義為是否是臟數(shù)據(jù)。

          ??@Override
          ??public?int?insert(String?statement,?Object?parameter)?{
          ????return?update(statement,?parameter);
          ??}

          ??@Override
          ??public?int?update(String?statement,?Object?parameter)?{
          ????try?{
          ??????dirty?=?true;
          ??????MappedStatement?ms?=?configuration.getMappedStatement(statement);
          ??????return?executor.update(ms,?wrapCollection(parameter));
          ????}?catch?(Exception?e)?{
          ??????throw?ExceptionFactory.wrapException("Error?updating?database.??Cause:?"?+?e,?e);
          ????}?finally?{
          ??????ErrorContext.instance().reset();
          ????}
          ??}

          源碼很明確,只要執(zhí)行update操作,就設(shè)置dirty=true。insert、delete最終也是執(zhí)行update操作。

          只有在執(zhí)行完commit()、rollback()、close()等方法后,才會(huì)再次設(shè)置dirty=false。

          ??@Override
          ??public?void?commit(boolean?force)?{
          ????try?{
          ??????executor.commit(isCommitOrRollbackRequired(force));
          ??????dirty?=?false;
          ????}?catch?(Exception?e)?{
          ??????throw?ExceptionFactory.wrapException("Error?committing?transaction.??Cause:?"?+?e,?e);
          ????}?finally?{
          ??????ErrorContext.instance().reset();
          ????}
          ??}

          因此,得出結(jié)論:autoCommit=false,但是沒(méi)有手動(dòng)commit,在sqlSession.close()時(shí),Mybatis會(huì)將事務(wù)進(jìn)行rollback()操作,然后才執(zhí)行conn.close()關(guān)閉連接,當(dāng)然數(shù)據(jù)最終也就沒(méi)能持久化到數(shù)據(jù)庫(kù)中了。


          3. autoCommit=false,沒(méi)有commit,也沒(méi)有close,會(huì)發(fā)生什么?

          studentMapper.insertStudent(student);

          干脆,就這一句話,即不commit,也不close。

          結(jié)論:insert后,jvm結(jié)束前,如果事務(wù)隔離級(jí)別是read uncommitted,我們可以查到該條記錄。jvm結(jié)束后,事務(wù)被rollback(),記錄消失。通過(guò)斷點(diǎn)debug方式,你可以看到效果。

          這說(shuō)明JDBC驅(qū)動(dòng)實(shí)現(xiàn),已經(jīng)Kao慮到這樣的特例情況,底層已經(jīng)有相應(yīng)的處理機(jī)制了。這也超出了我們的探究范圍。


          但是,一萬(wàn)個(gè)屌絲程序員會(huì)對(duì)你說(shuō):Don't do it like this. Go right way。

          警告:請(qǐng)按正確的try-catch-finally編程方式處理事務(wù),若不從,本人概不負(fù)責(zé)后果。


          注:無(wú)參的openSession()方法,會(huì)自動(dòng)設(shè)置autoCommit=false。


          總結(jié):Mybatis的JdbcTransaction,和純粹的Jdbc事務(wù),幾乎沒(méi)有差別,它僅是擴(kuò)展支持了連接池的connection。另外,需要明確,無(wú)論你是否手動(dòng)處理了事務(wù),只要是對(duì)數(shù)據(jù)庫(kù)進(jìn)行任何update操作(update、delete、insert),都一定是在事務(wù)中進(jìn)行的,這是數(shù)據(jù)庫(kù)的設(shè)計(jì)規(guī)范之一。讀完本篇文章,是否顛覆了你心中目前對(duì)事務(wù)的理解呢?


          ?--END--


          ? 推薦

          公眾號(hào)ID|javabaiwen

          小編微信|619531440


          每天分享技術(shù)干貨

          視頻|電子書|面試題|開(kāi)發(fā)經(jīng)驗(yàn)

          瀏覽 19
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  九九色在线播放 | 一起操电影网 | 成人性生交大片免费看网站2023年 | 国产 欧美 日韩 a | 最近中文字幕免费MV第一季歌词十 |