Spring事務(wù)_06_Spring事務(wù)常見(jiàn)問(wèn)題

1.Jdbc訪問(wèn)數(shù)據(jù)庫(kù)

public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;

     public int insertUser(User user){
        String sqlStr = "insert into t_user (user_name,password,credits)values(?,?,?)";
        return jdbcTemplate.update(sqlStr,new Object[]{user.getUserName()
        ,user.getPassword(),user.getCredits()});
    }
}

在默認(rèn)情況下,dataSource數(shù)據(jù)源的autoCommit被設(shè)置為true,這也意味著所有通過(guò)jdbcTemplate執(zhí)行的語(yǔ)句馬上提交,沒(méi)有事務(wù)。所以不使用Spring事務(wù)也可以進(jìn)行數(shù)據(jù)庫(kù)操作。

配置Spring事務(wù)的時(shí)候首先要確定數(shù)據(jù)庫(kù)支持Spring事務(wù),如果使用MyISAM引擎的MySQL數(shù)據(jù)庫(kù),這時(shí)即使配置了,也沒(méi)有實(shí)際價(jià)值。

2.Hibernate訪問(wèn)數(shù)據(jù)庫(kù)

Hibernate的事務(wù)管理有其自身的意義,它和Hibernate一級(jí)緩存存在密切的關(guān)系,當(dāng)調(diào)用Session的save、update等方法時(shí),Hibernate并不直接向數(shù)據(jù)庫(kù)發(fā)送SQL語(yǔ)句,只在提交事務(wù)或flush一級(jí)緩存時(shí)才真正向數(shù)據(jù)庫(kù)發(fā)送SQL。

因此,數(shù)據(jù)庫(kù)不支持事務(wù),Hibernate的事務(wù)管理也有一定的好處,不會(huì)對(duì)數(shù)據(jù)庫(kù)的操作產(chǎn)生負(fù)面的影響。如果使用Hibernate的數(shù)據(jù)訪問(wèn)技術(shù),沒(méi)有理由不配置HibernateTransactionManager.

3.應(yīng)用分層

Spring框架所提供的各種好處(如AOP、注解增強(qiáng)、注解MVC)的唯一前提就是讓POJO的類變?yōu)橐粋€(gè)受Spring容器管理的Bean,除此之外沒(méi)有其他任何要求。因此一個(gè)類可以同時(shí)是Contorller,也可以注解為Service,也可以注解為Dao.

4.事務(wù)方法嵌套調(diào)用

  • Spring事務(wù)傳播機(jī)制
    • Spring對(duì)事務(wù)控制的支持統(tǒng)一在TransactionDefinition類中描述。

        事務(wù)的傳播行為
        事務(wù)的隔離級(jí)別
        事務(wù)的過(guò)期時(shí)間
        事務(wù)的讀寫特性
      
    • 事務(wù)的7種傳播行為

        事務(wù)默認(rèn)的PROPAGATION_REQUIRED適合絕代大多數(shù)的情況,如果存在事務(wù)就加入
        如果不存在事務(wù)就創(chuàng)建
      
  • 相互嵌套的方法
    • 多個(gè)方法嵌套,事務(wù)直接合并。

5.多線程事務(wù)問(wèn)題

  • 由于Spring管理器是通過(guò)線程相關(guān)的ThreadLocal來(lái)保存數(shù)據(jù)訪問(wèn)的基礎(chǔ)設(shè)施(Connection實(shí)例),在結(jié)合IOC和AOP實(shí)現(xiàn)高級(jí)聲明式事務(wù)的的功能,所以Spring的事務(wù)天然的和事務(wù)有千絲萬(wàn)縷的聯(lián)系。
  • 在Web程序本身就是多線程的,Web容器為一個(gè)HTTP請(qǐng)求創(chuàng)建一個(gè)獨(dú)立的線程(實(shí)際上使用的是共享的線程池)。所以有此請(qǐng)求鎖牽涉到的Spring容器中的Bean也運(yùn)行與多線程的環(huán)境下。
  • 在多數(shù)情況下Spring的Bean都是單實(shí)例的(singleton),單實(shí)例Bean的最大好處就是線程無(wú)關(guān)性,不存在多線程并發(fā)的問(wèn)題,也就是線程安全的。
  • 一個(gè)類能夠以單實(shí)例的方式運(yùn)行的前提是“無(wú)狀態(tài)”;即一個(gè)類不能擁有狀態(tài)話的成員變量。我們知道,在傳統(tǒng)的編程中。Dao必須持有一個(gè)Connection,而Connection即是狀態(tài)化的對(duì)象。所以傳統(tǒng)的DAO不能做成單實(shí)例的,每次要用時(shí)都必須創(chuàng)建一個(gè)新的實(shí)例。傳統(tǒng)的Service由于內(nèi)部包含了若干個(gè)有狀態(tài)的DAO成員變量,所以基本也是有狀態(tài)的。
  • 但在Spring中,Dao和Service都以單實(shí)例的方式存在。Spring是通過(guò)ThreadLocal將有狀態(tài)的變量(Connection)本地線程化,達(dá)到另一個(gè)層面上的“線程無(wú)關(guān)”,從而實(shí)現(xiàn)線程安全。Spring不予余力將有狀態(tài)的對(duì)象無(wú)狀態(tài)化,就是達(dá)到單實(shí)例化Bean的目的。
  • Spring中事務(wù)時(shí)線程獨(dú)立的。在相同的線程進(jìn)行相互嵌套調(diào)用的事務(wù)方法工作于相同的事務(wù)中。如果這些相互前臺(tái)的方法工作在不同的線程中,則不同線程下的事務(wù)方法工作在獨(dú)立的事務(wù)中。

6.Spring應(yīng)對(duì)混合框架的事務(wù)管理

  • Spring中底層的ORM框架同底層JDBC技術(shù)的整合使用。Spring事務(wù)對(duì)每種數(shù)據(jù)訪問(wèn)技術(shù)提供了響應(yīng)的事務(wù)管理器,但是Spring當(dāng)遇到使用高端的ORM(Hibernate,JPA,JDO)框架,同時(shí)采用一個(gè)JDBC技術(shù)(SpringJDBC,Ibatis)時(shí),由于前者的會(huì)話Session是對(duì)后者連接(Connection)的封裝,Spring會(huì)足夠只能的在同一個(gè)事物線程讓前者的會(huì)話封裝后者的連接。我們只要直接采用前者的事務(wù)管理器就可以。
  • 但在使用Hibernate技術(shù)時(shí),Session的提交不是真正的提交。

7.不能實(shí)施Spring事務(wù)的方法

  • Spring事務(wù)管理是基于接口代理或動(dòng)態(tài)字節(jié)碼技術(shù),通過(guò)AOP試試事務(wù)增強(qiáng)的。
  • 對(duì)基于接口動(dòng)態(tài)代理的AOP事務(wù)增強(qiáng)來(lái)說(shuō),由于接口的方法必然是public的,這就要求實(shí)現(xiàn)類的實(shí)現(xiàn)方法也必須是public的,不能是protected或者private等,同時(shí)不能使用static的修飾符。所以實(shí)施接口代理的方法只能使用public或public final修飾符的方法,其他方法不可能被動(dòng)態(tài)代理,響應(yīng)的也就不能實(shí)施AOP增強(qiáng),換句話話說(shuō),即不能進(jìn)行Spring事務(wù)增強(qiáng)。
  • 基于CGLib字節(jié)碼動(dòng)態(tài)代理的方案是通過(guò)擴(kuò)展被增強(qiáng)的類,動(dòng)態(tài)創(chuàng)建子類的方式進(jìn)行AOP增強(qiáng)織入的。由于使用final,static ,private 修飾符的方法都不能被子類覆蓋,響應(yīng)的,這些方法將無(wú)法實(shí)施AOP增強(qiáng)。所以方法名必須特別注意這些修飾符的使用,以免方法不小心稱為事務(wù)管理的漏網(wǎng)之魚(yú)。
  • 這里不能被Spring事務(wù)增強(qiáng)的方法和可被Spring事務(wù)增強(qiáng)的方法唯一的區(qū)別在于使否可主動(dòng)啟動(dòng)一個(gè)新事物;不被Spring事務(wù)增強(qiáng)的方法是不能啟動(dòng)一個(gè)新事務(wù)的,只有被Spring事務(wù)增強(qiáng)的方法才能主動(dòng)啟動(dòng)一個(gè)新事務(wù)。對(duì)于事務(wù)傳播來(lái)說(shuō),二者是相同的,兩者都不會(huì)造成數(shù)據(jù)連接的泄露問(wèn)題。如果這些“特殊方法”被無(wú)事務(wù)上下文的方法調(diào)用,則他們就工作者無(wú)事務(wù)上下文中;反之,如果被具有事務(wù)事務(wù)上下文的方法調(diào)用,則他們就工作在事務(wù)的上下文中。
  • 對(duì)于private方法,由于最終都會(huì)被Public方法封裝后再開(kāi)始被外部調(diào)用。而public方法都是被事務(wù)增強(qiáng)的,所以基本上沒(méi)有什么問(wèn)題。在實(shí)際的開(kāi)發(fā)中,最容易造成隱患的是基于CGLib的動(dòng)態(tài)代理是的“public static”和public final這兩種特殊方法。原因是他們本身是public的。因此可以直接被外部類調(diào)用。只要調(diào)用者沒(méi)有事務(wù)上下文,這些特殊的方法就運(yùn)行在沒(méi)有事務(wù)的。

8.數(shù)據(jù)連接泄露問(wèn)題

    public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    Assert.notNull(dataSource, "No DataSource specified");

    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
        conHolder.requested();
        if (!conHolder.hasConnection()) {
            logger.debug("Fetching resumed JDBC Connection from DataSource");
            conHolder.setConnection(dataSource.getConnection());
        }
        return conHolder.getConnection();
    }
    // Else we either got no holder or an empty thread-bound holder here.

    logger.debug("Fetching JDBC Connection from DataSource");
    Connection con = dataSource.getConnection();

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
        logger.debug("Registering transaction synchronization for JDBC Connection");
        // Use same Connection for further JDBC actions within the transaction.
        // Thread-bound object will get removed by synchronization at transaction completion.
        ConnectionHolder holderToUse = conHolder;
        if (holderToUse == null) {
            holderToUse = new ConnectionHolder(con);
        }
        else {
            holderToUse.setConnection(con);
        }
        holderToUse.requested();
        TransactionSynchronizationManager.registerSynchronization(
                new ConnectionSynchronization(holderToUse, dataSource));
        holderToUse.setSynchronizedWithTransaction(true);
        if (holderToUse != conHolder) {
            TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
        }
    }

    return con;
}
  • Spring提供一個(gè)能從當(dāng)前事務(wù)上線文中獲取綁定數(shù)據(jù)連接的工具,以上為DataSourceUtils。Spring強(qiáng)調(diào)使用DataSourceUtils工具獲取連接,Spring的JdbcTemplate內(nèi)部也是通過(guò)DataSourceUtils來(lái)獲得連接的。DataSourceUtils提供了釋放連接的實(shí)現(xiàn)。
  • 但如果DataSourceUtils沒(méi)有在事務(wù)的上下文的方法中使用getConnection獲取連接,依然會(huì)造成數(shù)據(jù)連接泄露。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,688評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,285評(píng)論 6 342
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,823評(píng)論 18 399
  • application的配置屬性。 這些屬性是否生效取決于對(duì)應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,544評(píng)論 1 27
  • 這篇短篇斷斷續(xù)續(xù)寫了好久,算是閑來(lái)無(wú)事,純屬娛樂(lè),謹(jǐn)致所有碼農(nóng)。趁元旦比較閑,一鼓作氣草草擱筆。還望適度拍磚。有意...
    2gua閱讀 382評(píng)論 2 1

友情鏈接更多精彩內(nèi)容