{"id":10008260,"date":"2023-09-10T23:53:44","date_gmt":"2023-09-10T15:53:44","guid":{"rendered":"https:\/\/blog.itmax.cn\/?p=10008260"},"modified":"2023-09-10T23:53:44","modified_gmt":"2023-09-10T15:53:44","slug":"%e8%81%8a%e8%81%8atransactionsynchronization%e7%9a%84invokeaftercompletion","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10008260","title":{"rendered":"\u804a\u804aTransactionSynchronization\u7684invokeAfterCompletion"},"content":{"rendered":"<h2>\u5e8f<\/h2>\n<p>\u672c\u6587\u4e3b\u8981\u7814\u7a76\u4e00\u4e0bTransactionSynchronization\u7684invokeAfterCompletion<\/p>\n<h2>afterCompletion<\/h2>\n<p>org\/springframework\/transaction\/support\/TransactionSynchronization.java<\/p>\n<pre><code>public interface TransactionSynchronization extends Flushable {\n\n    \/** Completion status in case of proper commit. *\/\n    int STATUS_COMMITTED = 0;\n\n    \/** Completion status in case of proper rollback. *\/\n    int STATUS_ROLLED_BACK = 1;\n\n    \/** Completion status in case of heuristic mixed completion or system errors. *\/\n    int STATUS_UNKNOWN = 2;\n\n    \/\/......\n\n    \/**\n     * Invoked after transaction commit. Can perform further operations right\n     * &lt;i&gt;after&lt;\/i&gt; the main transaction has &lt;i&gt;successfully&lt;\/i&gt; committed.\n     * &lt;p&gt;Can e.g. commit further operations that are supposed to follow on a successful\n     * commit of the main transaction, like confirmation messages or emails.\n     * &lt;p&gt;&lt;b&gt;NOTE:&lt;\/b&gt; The transaction will have been committed already, but the\n     * transactional resources might still be active and accessible. As a consequence,\n     * any data access code triggered at this point will still &quot;participate&quot; in the\n     * original transaction, allowing to perform some cleanup (with no commit following\n     * anymore!), unless it explicitly declares that it needs to run in a separate\n     * transaction. Hence: &lt;b&gt;Use {@code PROPAGATION_REQUIRES_NEW} for any\n     * transactional operation that is called from here.&lt;\/b&gt;\n     * @throws RuntimeException in case of errors; will be &lt;b&gt;propagated to the caller&lt;\/b&gt;\n     * (note: do not throw TransactionException subclasses here!)\n     *\/\n    default void afterCommit() {\n    }\n\n    \/**\n     * Invoked after transaction commit\/rollback.\n     * Can perform resource cleanup &lt;i&gt;after&lt;\/i&gt; transaction completion.\n     * &lt;p&gt;&lt;b&gt;NOTE:&lt;\/b&gt; The transaction will have been committed or rolled back already,\n     * but the transactional resources might still be active and accessible. As a\n     * consequence, any data access code triggered at this point will still &quot;participate&quot;\n     * in the original transaction, allowing to perform some cleanup (with no commit\n     * following anymore!), unless it explicitly declares that it needs to run in a\n     * separate transaction. Hence: &lt;b&gt;Use {@code PROPAGATION_REQUIRES_NEW}\n     * for any transactional operation that is called from here.&lt;\/b&gt;\n     * @param status completion status according to the {@code STATUS_*} constants\n     * @throws RuntimeException in case of errors; will be &lt;b&gt;logged but not propagated&lt;\/b&gt;\n     * (note: do not throw TransactionException subclasses here!)\n     * @see #STATUS_COMMITTED\n     * @see #STATUS_ROLLED_BACK\n     * @see #STATUS_UNKNOWN\n     * @see #beforeCompletion\n     *\/\n    default void afterCompletion(int status) {\n    }\n\n}<\/code><\/pre>\n<blockquote><p>afterCompletion\u65b9\u6cd5\u6709\u5165\u53c2status\uff0c\u8868\u793a\u4e8b\u52a1\u7ed3\u675f\u65f6\u5019\u7684\u72b6\u6001\uff0c0\u8868\u793a\u4e8b\u52a1\u5df2\u63d0\u4ea4\uff0c1\u8868\u793a\u4e8b\u52a1\u5df2\u56de\u6eda\uff0c2\u8868\u793a\u4e8b\u52a1\u672a\u77e5\uff1b\u4e0eafterCommit\u7684\u4e00\u4e2a\u6700\u91cd\u8981\u7684\u533a\u522b\u662fafterCompletion\u7684\u5f02\u5e38\u4f1a\u88ab\u6355\u83b7\uff0c\u4e0d\u50cfafterCommit\u4f1a\u629b\u7ed9\u8c03\u7528\u65b9<\/p><\/blockquote>\n<h2>invokeAfterCompletion<\/h2>\n<p>org\/springframework\/transaction\/support\/TransactionSynchronizationUtils.java<\/p>\n<pre><code>    \/**\n     * Actually invoke the {@code afterCompletion} methods of the\n     * given Spring TransactionSynchronization objects.\n     * @param synchronizations a List of TransactionSynchronization objects\n     * @param completionStatus the completion status according to the\n     * constants in the TransactionSynchronization interface\n     * @see TransactionSynchronization#afterCompletion(int)\n     * @see TransactionSynchronization#STATUS_COMMITTED\n     * @see TransactionSynchronization#STATUS_ROLLED_BACK\n     * @see TransactionSynchronization#STATUS_UNKNOWN\n     *\/\n    public static void invokeAfterCompletion(@Nullable List&lt;TransactionSynchronization&gt; synchronizations,\n            int completionStatus) {\n\n        if (synchronizations != null) {\n            for (TransactionSynchronization synchronization : synchronizations) {\n                try {\n                    synchronization.afterCompletion(completionStatus);\n                }\n                catch (Throwable tsex) {\n                    logger.error(&quot;TransactionSynchronization.afterCompletion threw exception&quot;, tsex);\n                }\n            }\n        }\n    }<\/code><\/pre>\n<blockquote><p>\u53ef\u4ee5\u770b\u5230TransactionSynchronizationUtils\u7684invokeAfterCompletion\u65b9\u6cd5\u4f1a\u904d\u5386synchronizations\uff0c\u6328\u4e2a\u6267\u884cafterCompletion\uff0c\u6ce8\u610f\u8fd9\u91cccatch\u4e86Throwable\u5f02\u5e38\uff0c\u8fdb\u884c\u4e86error\u7ea7\u522b\u7684log<\/p><\/blockquote>\n<h2>AbstractPlatformTransactionManager<\/h2>\n<p>org\/springframework\/transaction\/support\/AbstractPlatformTransactionManager.java<\/p>\n<pre><code>    \/**\n     * Actually invoke the {@code afterCompletion} methods of the\n     * given Spring TransactionSynchronization objects.\n     * &lt;p&gt;To be called by this abstract manager itself, or by special implementations\n     * of the {@code registerAfterCompletionWithExistingTransaction} callback.\n     * @param synchronizations a List of TransactionSynchronization objects\n     * @param completionStatus the completion status according to the\n     * constants in the TransactionSynchronization interface\n     * @see #registerAfterCompletionWithExistingTransaction(Object, java.util.List)\n     * @see TransactionSynchronization#STATUS_COMMITTED\n     * @see TransactionSynchronization#STATUS_ROLLED_BACK\n     * @see TransactionSynchronization#STATUS_UNKNOWN\n     *\/\n    protected final void invokeAfterCompletion(List&lt;TransactionSynchronization&gt; synchronizations, int completionStatus) {\n        TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus);\n    }\n\n    \/**\n     * Trigger {@code afterCompletion} callbacks.\n     * @param status object representing the transaction\n     * @param completionStatus completion status according to TransactionSynchronization constants\n     *\/\n    private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {\n        if (status.isNewSynchronization()) {\n            List&lt;TransactionSynchronization&gt; synchronizations = TransactionSynchronizationManager.getSynchronizations();\n            TransactionSynchronizationManager.clearSynchronization();\n            if (!status.hasTransaction() || status.isNewTransaction()) {\n                if (status.isDebug()) {\n                    logger.trace(&quot;Triggering afterCompletion synchronization&quot;);\n                }\n                \/\/ No transaction or new transaction for the current scope -&gt;\n                \/\/ invoke the afterCompletion callbacks immediately\n                invokeAfterCompletion(synchronizations, completionStatus);\n            }\n            else if (!synchronizations.isEmpty()) {\n                \/\/ Existing transaction that we participate in, controlled outside\n                \/\/ of the scope of this Spring transaction manager -&gt; try to register\n                \/\/ an afterCompletion callback with the existing (JTA) transaction.\n                registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);\n            }\n        }\n    }<\/code><\/pre>\n<blockquote><p>AbstractPlatformTransactionManager\u7684invokeAfterCompletion\u59d4\u6258\u7ed9\u4e86TransactionSynchronizationUtils.invokeAfterCompletion\uff1btriggerAfterCompletion\u4e3b\u8981\u662f\u6839\u636e\u4e8b\u52a1\u72b6\u6001\u6267\u884c\u4e0d\u540c\u903b\u8f91\uff0c\u5206\u522b\u662finvokeAfterCompletion\u4e0eregisterAfterCompletionWithExistingTransaction\uff0c\u540e\u8005\u4e3b\u8981\u662fJTA\u4e4b\u7c7b\u7684\u573a\u666f\uff0c\u5b83\u56de\u4f20\u7684status\u662fSTATUS_UNKNOWN<\/p><\/blockquote>\n<h2>\u5c0f\u7ed3<\/h2>\n<p>afterCompletion\u65b9\u6cd5\u6709\u5165\u53c2status\uff0c\u8868\u793a\u4e8b\u52a1\u7ed3\u675f\u65f6\u5019\u7684\u72b6\u6001\uff0c0\u8868\u793a\u4e8b\u52a1\u5df2\u63d0\u4ea4\uff0c1\u8868\u793a\u4e8b\u52a1\u5df2\u56de\u6eda\uff0c2\u8868\u793a\u4e8b\u52a1\u672a\u77e5(<code>\u4e00\u822c\u662fJTA\u76f8\u5173<\/code>)\uff1b\u4e0eafterCommit\u7684\u4e00\u4e2a\u6700\u91cd\u8981\u7684\u533a\u522b\u662fafterCompletion\u7684\u5f02\u5e38(<code>Throwable<\/code>)\u4f1a\u88ab\u6355\u83b7\uff0c\u4e0d\u50cfafterCommit\u4f1a\u629b\u7ed9\u8c03\u7528\u65b9<\/p>\n<h2>doc<\/h2>\n<ul>\n<li><a target=\"_blank\" href=\"https:\/\/link.segmentfault.com\/?enc=mLS3ei0FyuNfKHGAeo5fKw%3D%3D.CspQp3xCbtNXUBcUpMcg75ZLYJnzPLG5xFyEAvBAcQLLjzzlxFSsEAhvmr78yyfoRjAZ170E%2FC6ZKx%2BNlWvLvA%3D%3D\" rel=\"noopener noreferrer\">\u804a\u804aspring\u7684TransactionSynchronizationAdapter<\/a><\/li>\n<\/ul>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000044201604\">https:\/\/segmentfault.com\/a\/1190000044201604<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5e8f \u672c\u6587\u4e3b\u8981\u7814\u7a76\u4e00\u4e0bTransactionSynchronization\u7684invokeAfterComplet [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10008260","post","type-post","status-publish","format-standard","hentry","category-share"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10008260","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10008260"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10008260\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10008260"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10008260"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10008260"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}