中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring是如何給事務實現傳播特性的

發布時間:2021-10-29 20:20:19 來源:億速云 閱讀:170 作者:iii 欄目:編程語言

這篇文章主要介紹“Spring是如何給事務實現傳播特性的”,在日常操作中,相信很多人在Spring是如何給事務實現傳播特性的問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring是如何給事務實現傳播特性的”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

事務

事務是什么?

它是一級原子性的SQL操作,一個獨立的工作單元。如果工作單元中的SQL語句執行成功,那會全部成功,一個失敗就會全部回滾。

與數據庫的事務同時為大眾熟知的是ACID。即數據庫的原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。就像應用內為了線程之間的互斥,線程安全等,需要做大量的工作,數據庫為了  ACID,也做了許多的工作。

隔離級別

SQL 的標準中定義了四種隔離級別,規定了哪些是事務之間可見的,哪些是事務內可見的。

READ UNCOMMITTED (未提交讀) --> 兩個事務間,一個的事務還沒提交,但被另一個看到了。

READ COMMITTED (提交讀) --> 兩個事務間,只有一個事務提交之后,另一個事務才能看到。

REPEATABLE READ (可重復讀)--> 一個事務執行中,多次讀到的結果是一樣的,即使其他事務做了修改,也先「看不見」

SERIALIZABLE (可串行化)--> 最高隔離級別,強制事務串行執行。

由于這些隔離級別,會造成所謂的「臟讀」、「幻讀」、「不可重復讀」等問題,所以需要根據具體的場景選擇適用的。

如何設置隔離級別

對于 MySQL 的隔離級別,可以全局的,也可以設置 Session 級別的。

官方文檔設置語法如下:

Spring是如何給事務實現傳播特性的

我們通過客戶端連接到 MySQL Server 的時候,可以做一些配置,通過jdbc的 URL 你也能看的出來,這樣設置的就是 Session  級別的。

參考上面的官方文檔,設置 session 隔離級別的命令是它:

set session transaction isolation level SERIALIZABLE;

注意,MySQL 默認的隔離級別是 REPEATABLE READ,我的改過。同時,這里查詢當前隔離級別的SQL,舊版本的是SELECT  @@TX_ISOLATION;,新版本的是SELECT @@Transaction_ISOLATION; 注意區分。

Spring是如何給事務實現傳播特性的

Spring 事務又是怎么回事

看過了數據庫的隔離級別之后,我們再來看 Spring 里的實現。

在 Spring 里,隔離級別的定義有五種,四個和數據庫的一致,另外包含一個 DEFAULT,代表不具體設置,直接使用數據庫定義的。

咱們看到數據庫的隔離級別可以設置 GLOBAL 級別的,也可以設置 SESSION 級別的,每個 SESSION 則代表的是一個連接。而在Spring  內,我們又是通過一個個獨立的「連接」來操作數據庫,完成CRUD。到這兒咱們應該就能知道,在 Spring 層面的設置,是通過 session 級別的  隔離來設置的,從而和數據庫里事務隔離級別做了對應來實現。

那傳播特性又是怎么回事呢?既然數據庫并不直接支持這樣的特性,Spring 又根據不同的傳播特性要求,來迂回實現了。

總結起來,對于級聯操作中,如果是REQUIRED_NEW這種的情況,所謂的掛起當前事務,開啟新的事務,是 Spring 又去申請了一個新的  Connection,這樣就會對應到一個新的事務上,然后將這個連接綁定到當前線程,再繼續執行;

對于嵌套事務,底層則是通過數據庫的 SAVEPOINT 來實現所謂的「子事務」

Spring是如何給事務實現傳播特性的

如果你熟悉代碼 DEBUG 過程中每個方法對應的 Frame,可以類比一下,如果執行失敗回滾的時候,可以指定回滾到當前事務的某個  SAVEPOINT,不需要全部回滾。

在 Spring 層面,是通過 JDBC 3.0來實現的,看下面這段代碼注釋。

* <p>This transaction manager supports nested transactions via the JDBC 3.0 * {@link java.sql.Savepoint} mechanism. The * {@link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults * to "true", since nested transactions will work without restrictions on JDBC * drivers that support savepoints (such as the Oracle JDBC driver).

事務掛起的部分代碼如下:

/**    * Suspend the given transaction. Suspends transaction synchronization first,    * then delegates to the {@code doSuspend} template method.    * @param transaction the current transaction object    * (or {@code null} to just suspend active synchronizations, if any)    * @return an object that holds suspended resources    * (or {@code null} if neither transaction nor synchronization active)    * @see #doSuspend    * @see #resume    */   @Nullable   protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {     if (TransactionSynchronizationManager.isSynchronizationActive()) {       List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();       try {         Object suspendedResources = null;         if (transaction != null) {           suspendedResources = doSuspend(transaction);         }         String name = TransactionSynchronizationManager.getCurrentTransactionName();         TransactionSynchronizationManager.setCurrentTransactionName(null);         boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();         TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);         Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();         TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);         boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();         TransactionSynchronizationManager.setActualTransactionActive(false);         return new SuspendedResourcesHolder(             suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);       }   }

邏輯在 doSuspend里,繼續看

@Override   protected Object doSuspend(Object transaction) {     DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;     txObject.setConnectionHolder(null);     return TransactionSynchronizationManager.unbindResource(obtainDataSource());   }    @Override   protected void doResume(@Nullable Object transaction, Object suspendedResources) {     TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);   }

然后對應的bind 和 unbind 操作,是在ThreadLocal 對象里,將資源對象綁定或移出當前線程對應的 resources 來實現的。

private static final ThreadLocal<Map<Object, Object>> resources =       new NamedThreadLocal<>("Transactional resources"); /**    * Bind the given resource for the given key to the current thread.    * @param key the key to bind the value to (usually the resource factory)    * @param value the value to bind (usually the active resource object)    * @throws IllegalStateException if there is already a value bound to the thread    * @see ResourceTransactionManager#getResourceFactory()    */   public static void bindResource(Object key, Object value) throws IllegalStateException {     Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);     Assert.notNull(value, "Value must not be null");     Map<Object, Object> map = resources.get();     // set ThreadLocal Map if none found     if (map == null) {       map = new HashMap<>();       resources.set(map);     }     Object oldValue = map.put(actualKey, value);     // Transparently suppress a ResourceHolder that was marked as void...     if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {       oldValue = null;     }   }

對比上面的說明和代碼,這兩個傳播特性的區別也很明了了:

NESTED 的特性,本質上還是同一個事務的不同保存點,如果涉及到外層事務回滾,則內層的也將會被回滾;

REQUIRED_NEW 的實現對應的是一個新的事務,拿到的是新的資源,所以外層事務回滾時,不影響內層事務。

到此,關于“Spring是如何給事務實現傳播特性的”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

咸宁市| 三台县| 唐河县| 秀山| 陵水| 苍溪县| 丹江口市| 锡林浩特市| 余姚市| 墨竹工卡县| 阿克| 鄂托克前旗| 香格里拉县| 蒲江县| 民和| 屏边| 衢州市| 丰都县| 香格里拉县| 溧阳市| 旌德县| 九江市| 阜南县| 长春市| 涿州市| 竹北市| 马尔康县| 健康| 宁明县| 穆棱市| 鄯善县| 五家渠市| 眉山市| 繁昌县| 桑日县| 内黄县| 阿瓦提县| 聂拉木县| 得荣县| 尼勒克县| 汕头市|