日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Spring事务和MySQL事务详解面试

發(fā)布時(shí)間:2024/3/12 数据库 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring事务和MySQL事务详解面试 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 數(shù)據(jù)庫事務(wù)
      • 事務(wù)是什么
      • 事務(wù)的四大特性
    • MySQL事務(wù)隔離級別
      • 查看MySQL當(dāng)前事務(wù)隔離級別
      • MySQL默認(rèn)操作模式為自動(dòng)提交模式
    • JDBC處理事務(wù)
    • Spring事務(wù)
      • Spring的事務(wù)傳播
        • PROPAGATION_REQUIRED
        • PROPAGATION_SUPPORTS
        • PROPAGATION_MANDATORY
        • PROPAGATION_REQUIRES_NEW
        • PROPAGATION_NOT_SUPPORTED
        • PROPAGATION_NEVER
        • PROPAGATION_NESTED
      • Spring事務(wù)的隔離級別
      • Spring事務(wù)基本配置樣例

數(shù)據(jù)庫事務(wù)

事務(wù)是什么

是數(shù)據(jù)庫操作的最小工作單元,是作為單個(gè)邏輯工作單元執(zhí)行的一系列操作;這些操作作為一個(gè)整體一起向系統(tǒng)提交,要么都執(zhí)行、要么都不執(zhí)行;事務(wù)是一組不可再分割的操作集合。

事務(wù)的四大特性

  • 原子性
    事務(wù)是數(shù)據(jù)庫的邏輯工作單位,事務(wù)中包含的各操作要么都做,要么都不做

  • 一致性
    事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。

  • 隔離性
    一個(gè)事務(wù)的執(zhí)行不能被其它事務(wù)干擾。即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對其它并發(fā)事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。

  • 持續(xù)性
    也稱永久性,指一個(gè)事務(wù)一旦提交,它對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的。接下來的其它操作或故障不應(yīng)該對其執(zhí)行結(jié)果有任何影響。

  • MySQL事務(wù)隔離級別

    隔離級別隔離級別的值導(dǎo)致的問題
    Read-Uncommitted0導(dǎo)致臟讀
    Read-Committed1避免臟讀,允許不可重復(fù)讀和幻讀
    Repeatable-Read2MySQL默認(rèn)的隔離級別。避免臟讀,不可重復(fù)讀,允許幻讀
    Serializable3串行化讀,事務(wù)只能一個(gè)一個(gè)執(zhí)行,避免了 臟讀、不可重復(fù)讀、幻讀。執(zhí)行效率慢,使用時(shí)慎重

    1. 臟讀

    一個(gè)事務(wù)對數(shù)據(jù)進(jìn)行了增刪改查,但是未提交事務(wù)。另一個(gè)事物可以讀取到未提交的數(shù)據(jù),如果第一個(gè)事務(wù)進(jìn)行了回滾,那么第二個(gè)事務(wù)就讀到了臟數(shù)據(jù)。

    例子:

    領(lǐng)導(dǎo)給張三發(fā)工資,10000元已打到張三賬戶,但該事務(wù)還未提交,正好這時(shí)候張三去查詢工資,發(fā)現(xiàn)10000元已到賬。這時(shí)領(lǐng)導(dǎo)發(fā)現(xiàn)張三工資算多了5000元,于是回滾了事務(wù),修改了金額后將事務(wù)提交。最后張三實(shí)際到賬的只有5000元。

    2. 不可重復(fù)度

    一次事務(wù)發(fā)生了兩次讀操作,兩個(gè)讀操作之間發(fā)生了另一個(gè)事務(wù)對數(shù)據(jù)修改操作,這時(shí)候第一次和第二次讀到的數(shù)據(jù)不一致。

    不可重復(fù)度關(guān)注點(diǎn)在數(shù)據(jù)更新和刪除,通過行級鎖可以實(shí)現(xiàn)可重復(fù)讀的隔離級別。

    例子:

    張三需要轉(zhuǎn)正1000元,系統(tǒng)讀到卡余額有2000元,此時(shí)張三老婆正好需要轉(zhuǎn)正2000元,并且在張三提交事務(wù)前把2000元轉(zhuǎn)走了,當(dāng)張三提交轉(zhuǎn)賬是系統(tǒng)提示余額不足。

    3. 幻讀

    幻讀,指的是當(dāng)某個(gè)事務(wù)在讀取某個(gè)范圍內(nèi)的記錄時(shí),另外一個(gè)事務(wù)又在該范圍內(nèi)插入了新的記錄,當(dāng)之前的事務(wù)再次讀取該范圍的記錄時(shí),會(huì)產(chǎn)生幻行。

    相對于不可重復(fù)讀,幻讀更關(guān)注其它事務(wù)的新增數(shù)據(jù)。通過行級鎖可以避免不可重復(fù)讀,但無法解決幻讀的問題,想要解決幻讀,只能通過Serializable隔離級別來實(shí)現(xiàn)。

    例子:

    張三老婆準(zhǔn)備打印張三這個(gè)月的信用卡消費(fèi)記錄,經(jīng)查詢發(fā)現(xiàn)消費(fèi)了兩次共1000元,而這時(shí)張三剛按摩完準(zhǔn)備結(jié)賬,消費(fèi)了1000元,這時(shí)銀行記錄新增了一條1000元的消費(fèi)記錄。當(dāng)張三老婆將消費(fèi)記錄打印出來時(shí),發(fā)現(xiàn)總額變?yōu)榱?000元,這讓張三老婆很詫異。

    4. 串行化讀

    Serializable是最高的隔離級別,性能很低,一般很少用。在這級別下,事務(wù)是串行順序執(zhí)行的,不僅避免了臟讀、不可重復(fù)讀,還避免了幻讀。

    查看MySQL當(dāng)前事務(wù)隔離級別

    MySQL InnoDB默認(rèn)的事務(wù)隔離級別為REPEATABLE-READ

    mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+

    MySQL默認(rèn)操作模式為自動(dòng)提交模式

    除非顯示的開啟一個(gè)事務(wù),否則每個(gè)查詢都被當(dāng)成一個(gè)單獨(dú)的事務(wù)自動(dòng)執(zhí)行。可以通脫設(shè)置autocommit的值改變默認(rèn)的提交模式。

  • 查看當(dāng)前提交模式
  • mysql> show variables like 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+
  • 關(guān)閉自動(dòng)提交。0代表關(guān)閉,1代表開啟。
  • mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec)mysql> show variables like 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | OFF | +---------------+-------+

    JDBC處理事務(wù)

    Connection connection = null; PreparedStatement pstmt = null; ResultSet resultSet = null;try {Class.forName("com.mysql.jdbc.Driver");connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?characterEncoding=utf-8","username", "password");connection.setAutoCommit(false);// others ......connection.commit(); } catch (Exception e) {connection.rollback(); } finally {connection.setAutoCommit(true);// close connection }

    Spring事務(wù)

    Spring事務(wù)本質(zhì)是對數(shù)據(jù)庫事務(wù)的支持,如果數(shù)據(jù)庫不支持事務(wù)(例如MySQL的MyISAM引擎不支持事務(wù)),則Spring事務(wù)也不會(huì)生效。

    Spring的事務(wù)傳播

    事務(wù)傳播行為是指一個(gè)事務(wù)方法A被另一個(gè)事務(wù)方法B調(diào)用時(shí),這個(gè)事務(wù)A應(yīng)該如何處理。事務(wù)A應(yīng)該在事務(wù)B中運(yùn)行還是另起一個(gè)事務(wù),這個(gè)有事務(wù)A的傳播行為決定。

    事務(wù)傳播屬性定義TransactionDefinition

    int PROPAGATION_REQUIRED = 0; int PROPAGATION_SUPPORTS = 1; int PROPAGATION_MANDATORY = 2; int PROPAGATION_REQUIRES_NEW = 3; int PROPAGATION_NOT_SUPPORTED = 4; int PROPAGATION_NEVER = 5; int PROPAGATION_NESTED = 6; 常量名稱常量解釋
    PROPAGATION_REQUIRED支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是Spring 默認(rèn)的事務(wù)的傳播。
    PROPAGATION_SUPPORTS支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
    PROPAGATION_MANDATORY支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
    PROPAGATION_REQUIRES_NEW新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。新建的事務(wù)將和被掛起的事務(wù)沒有任何關(guān)系,是兩個(gè)獨(dú)立的事務(wù),外層事務(wù)失敗回滾之后, 不能回滾內(nèi)層事務(wù)執(zhí)行的結(jié)果,內(nèi)層事務(wù)失敗拋出異常,外層事務(wù)捕獲, 也可以不處理回滾操作。 使用JtaTransactionManager作為事務(wù)管理器
    PROPAGATION_NOT_SUPPORTED以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。使用JtaTransactionManager作為事務(wù)管理器
    PROPAGATION_NEVER以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
    PROPAGATION_NESTED如果一個(gè)活動(dòng)的事務(wù)存在,則運(yùn)行在一個(gè)嵌套的事務(wù)中。如果沒有活動(dòng)事務(wù),則按REQUIRED屬性執(zhí)行。它使用了一個(gè)單獨(dú)的事務(wù),這個(gè)事務(wù)擁有多個(gè)可以回滾的保存點(diǎn)。內(nèi)部事務(wù)的回滾不會(huì)對外部事務(wù)造成影響。它只對DataSourceTransactionManager事務(wù)管理器起效。

    PROPAGATION_REQUIRED

    如果存在一個(gè)事務(wù),則支持當(dāng)前事務(wù),如果沒有事務(wù)則開啟事務(wù)。

    如下例子,單獨(dú)調(diào)用methodB時(shí),當(dāng)前上下文沒有事務(wù),所以會(huì)開啟一個(gè)新的事務(wù)。

    調(diào)用methodA方法時(shí),因?yàn)楫?dāng)前上下文不存在事務(wù),所以會(huì)開啟一個(gè)新的事務(wù)。當(dāng)執(zhí)行到methodB時(shí),methodB發(fā)現(xiàn)當(dāng)前上下文有事務(wù),因此就加入到當(dāng)前事務(wù)A中來。

    @Transactional(propagation = Propagation.REQUIRED) public void methodA() {methodB();// do something }@Transactional(propagation = Propagation.REQUIRED) public void methodB() {// do something }

    PROPAGATION_SUPPORTS

    如果存在一個(gè)事務(wù),支持當(dāng)前事務(wù)。如果沒有事務(wù),則非事務(wù)的執(zhí)行.

    單獨(dú)的調(diào)用methodB時(shí),methodB方法是非事務(wù)的執(zhí)行的。當(dāng)調(diào)用methdA時(shí),methodB則加入了methodA的事務(wù)中,事務(wù)地執(zhí)行。

    @Transactional(propagation = Propagation.REQUIRED) public void methodA() {methodB();// do something }// 事務(wù)屬性為SUPPORTS @Transactional(propagation = Propagation.SUPPORTS) public void methodB() {// do something }

    PROPAGATION_MANDATORY

    如果已經(jīng)存在一個(gè)事務(wù),支持當(dāng)前事務(wù)。如果沒有一個(gè)活動(dòng)的事務(wù),則拋出異常。

    當(dāng)單獨(dú)調(diào)用methodB時(shí),因?yàn)楫?dāng)前沒有一個(gè)活動(dòng)的事務(wù),則會(huì)拋出異常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”)

    當(dāng)調(diào)用methodA時(shí),methodB則加入到methodA的事務(wù)中,以事務(wù)方式執(zhí)行。

    @Transactional(propagation = Propagation.REQUIRED) public void methodA() {methodB();// do something }@Transactional(propagation = Propagation.MANDATORY) public void methodB() {// do something }

    PROPAGATION_REQUIRES_NEW

    使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作為事務(wù)管理器。
    它會(huì)開啟一個(gè)新的事務(wù)。如果一個(gè)事務(wù)已經(jīng)存在,則先將這個(gè)存在的事務(wù)掛起。

    從下面代碼可以看出,事務(wù)B與事務(wù)A是兩個(gè)獨(dú)立的事務(wù),互不相干。事務(wù)B是否成功并不依賴于 事務(wù)A。如果methodA方法在調(diào)用methodB方法后的doSomeThingB方法失敗了,而methodB方法所做的結(jié)果依然被提交。而除了 methodB之外的其它代碼導(dǎo)致的結(jié)果卻被回滾了

    @Transactional(propagation = Propagation.REQUIRED) public void methodA() {doSomeThingA();methodB();doSomeThingB();// do something else }@Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() {// do something }

    當(dāng)調(diào)用methodA(),相當(dāng)于

    public static void main(){TransactionManager tm = null;try{//獲得一個(gè)JTA事務(wù)管理器tm = getTransactionManager();tm.begin();//開啟一個(gè)新的事務(wù)Transaction ts1 = tm.getTransaction();doSomeThing();tm.suspend();//掛起當(dāng)前事務(wù)try{tm.begin();//重新開啟第二個(gè)事務(wù)Transaction ts2 = tm.getTransaction();methodB();ts2.commit();//提交第二個(gè)事務(wù)} Catch(RunTimeException ex) {ts2.rollback();//回滾第二個(gè)事務(wù)} finally {//釋放資源}//methodB執(zhí)行完后,恢復(fù)第一個(gè)事務(wù)tm.resume(ts1);doSomeThingB();ts1.commit();//提交第一個(gè)事務(wù)} catch(RunTimeException ex) {ts1.rollback();//回滾第一個(gè)事務(wù)} finally {//釋放資源} }

    PROPAGATION_NOT_SUPPORTED

    總是非事務(wù)地執(zhí)行,并掛起任何存在的事務(wù)。

    使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務(wù)管理器。

    PROPAGATION_NEVER

    總是非事務(wù)地執(zhí)行,如果存在一個(gè)活動(dòng)事務(wù),則拋出異常。

    PROPAGATION_NESTED

    如果一個(gè)活動(dòng)的事務(wù)存在,則運(yùn)行在一個(gè)嵌套的事務(wù)中。

    如果沒有活動(dòng)事務(wù),則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。

    這是一個(gè)嵌套事務(wù),使用JDBC3.0驅(qū)動(dòng)時(shí),僅僅支持DataSourceTransactionManager作為事務(wù)管理器。 需要JDBC 驅(qū)動(dòng)的java.sql.Savepoint類。使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設(shè)為true(屬性值默認(rèn)為false)。

    @Transactional(propagation = Propagation.REQUIRED) methodA(){doSomeThingA();methodB();doSomeThingB(); }@Transactional(propagation = Propagation.NEWSTED) methodB(){// do something }

    單獨(dú)調(diào)用methodB方法,則按REQUIRED屬性執(zhí)行。如果調(diào)用methodA方法,則相當(dāng)于:

    main(){Connection con = null;Savepoint savepoint = null;try{con = getConnection();con.setAutoCommit(false);doSomeThingA();savepoint = con2.setSavepoint();try{methodB();} catch(RuntimeException ex) {con.rollback(savepoint);} finally {//釋放資源}doSomeThingB();con.commit();} catch(RuntimeException ex) {con.rollback();} finally {//釋放資源} }

    當(dāng)methodB方法調(diào)用之前,調(diào)用setSavepoint方法,保存當(dāng)前的狀態(tài)到savepoint。如果methodB方法調(diào)用失敗,則恢復(fù)到之前保存的狀態(tài)。

    需要注意的是,這時(shí)的事務(wù)并沒有進(jìn)行提交,如果后續(xù)的代碼(doSomeThingB()方法)調(diào)用失敗,則回滾包括methodB方法的所有操作。嵌套事務(wù)一個(gè)非常重要的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)。外層事務(wù)失敗時(shí),會(huì)回滾內(nèi)層事務(wù)所做的動(dòng)作。而內(nèi)層事務(wù)操作失敗并不會(huì)引起外層事務(wù)的回滾。

    Spring事務(wù)的隔離級別

    事務(wù)隔離級別定義TransactionDefinition

    int ISOLATION_DEFAULT = -1; int ISOLATION_READ_UNCOMMITTED = 1; int ISOLATION_READ_COMMITTED = 2; int ISOLATION_REPEATABLE_READ = 4; int ISOLATION_SERIALIZABLE = 8; 隔離級別解釋
    ISOLATION_DEFAULT這是個(gè) PlatfromTransactionManager 默認(rèn)的隔離級別, 使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級別。另外四個(gè)與 JDBC 的 隔離級別相對應(yīng)。
    ISOLATION_READ_UNCOMMITTED這是事務(wù)最低的隔離級別,它允許另外一個(gè)事務(wù)可以看 到這個(gè)事務(wù)未提交的數(shù)據(jù)。這種隔離級別會(huì)產(chǎn)生臟讀, 不可重復(fù)讀和幻像讀。
    ISOLATION_READ_COMMITTED保證一個(gè)事務(wù)修改的數(shù)據(jù)提交后才能被另外一個(gè)事務(wù)讀 取。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)。 ISOLATION_REPEATABLE_READ
    ISOLATION_SERIALIZABLE這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級別。事務(wù)被 處理為順序執(zhí)行。

    Spring事務(wù)基本配置樣例

    <aop:aspectj-autoproxy proxy-target-class="true"/><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/> </bean><tx:advice id="transactionAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="add*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/><tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/><tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/><tx:method name="login" propagation="NOT_SUPPORTED"/><tx:method name="query*" read-only="true"/></tx:attributes> </tx:advice><aop:config><aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/><aop:aspect ref="dataSource"><aop:pointcut id="transactionPointcut" expression="execution(public * com.gupaoedu..*.service..*Service.*(..))" /></aop:aspect> </aop:config>

    總結(jié)

    以上是生活随笔為你收集整理的Spring事务和MySQL事务详解面试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。