{"id":10008361,"date":"2024-02-18T21:00:18","date_gmt":"2024-02-18T13:00:18","guid":{"rendered":"https:\/\/blog.itmax.cn\/?p=10008361"},"modified":"2024-02-18T21:00:18","modified_gmt":"2024-02-18T13:00:18","slug":"spring%e4%ba%8b%e5%8a%a1%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10008361","title":{"rendered":"Spring\u4e8b\u52a1\u5b9e\u73b0\u539f\u7406"},"content":{"rendered":"<h2>1\u3001\u5f15\u8a00<\/h2>\n<p>spring\u7684spring-tx\u6a21\u5757\u63d0\u4f9b\u4e86\u5bf9\u4e8b\u52a1\u7ba1\u7406\u652f\u6301\uff0c\u4f7f\u7528spring\u4e8b\u52a1\u53ef\u4ee5\u8ba9\u6211\u4eec\u4ece\u590d\u6742\u7684\u4e8b\u52a1\u5904\u7406\u4e2d\u5f97\u5230\u89e3\u8131\uff0c\u65e0\u9700\u8981\u53bb\u5904\u7406\u83b7\u5f97\u8fde\u63a5\u3001\u5173\u95ed\u8fde\u63a5\u3001\u4e8b\u52a1\u63d0\u4ea4\u548c\u56de\u6eda\u7b49\u8fd9\u4e9b\u64cd\u4f5c\u3002<\/p>\n<p>spring\u4e8b\u52a1\u6709\u7f16\u7a0b\u5f0f\u4e8b\u52a1\u548c\u58f0\u660e\u5f0f\u4e8b\u52a1\u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f\u3002\u7f16\u7a0b\u5f0f\u4e8b\u52a1\u662f\u901a\u8fc7\u7f16\u5199\u4ee3\u7801\u6765\u7ba1\u7406\u4e8b\u52a1\u7684\u63d0\u4ea4\u3001\u56de\u6eda\u3001\u4ee5\u53ca\u4e8b\u52a1\u7684\u8fb9\u754c\u3002\u8fd9\u610f\u5473\u7740\u5f00\u53d1\u8005\u9700\u8981\u5728\u4ee3\u7801\u4e2d\u663e\u5f0f\u5730\u8c03\u7528\u4e8b\u52a1\u7684\u5f00\u59cb\u3001\u63d0\u4ea4\u548c\u56de\u6eda\u3002\u58f0\u660e\u5f0f\u4e8b\u52a1\u662f\u901a\u8fc7\u914d\u7f6e\u6765\u7ba1\u7406\u4e8b\u52a1\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u6ce8\u89e3\u6216XML\u914d\u7f6e\u6765\u5b9a\u4e49\u4e8b\u52a1\u7684\u8fb9\u754c\u548c\u5c5e\u6027\uff0c\u800c\u65e0\u9700\u663e\u5f0f\u7f16\u5199\u4e8b\u52a1\u7ba1\u7406\u7684\u4ee3\u7801\u3002<\/p>\n<p>\u4e0b\u9762\u6211\u4eec\u9010\u6b65\u5206\u6790spring\u6e90\u4ee3\u7801\uff0c\u7406\u89e3spring\u4e8b\u52a1\u7684\u5b9e\u73b0\u539f\u7406\u3002<\/p>\n<h2>2\u3001\u7f16\u7a0b\u5f0f\u4e8b\u52a1<\/h2>\n<h4>2.1 \u4f7f\u7528\u793a\u4f8b<\/h4>\n<pre><code>\/\/ transactionManager\u662f\u67d0\u4e00\u4e2a\u5177\u4f53\u7684PlatformTransactionManager\u5b9e\u73b0\u7c7b\u7684\u5bf9\u8c61\nprivate PlatformTransactionManager transactionManager;\n\n\n\/\/ \u5b9a\u4e49\u4e8b\u52a1\u5c5e\u6027\nDefaultTransactionDefinition def = new DefaultTransactionDefinition();\n\n\/\/ \u83b7\u53d6\u4e8b\u52a1\nTransactionStatus status = transactionManager.getTransaction(def);\n\ntry {\n    \/\/ \u6267\u884c\u6570\u636e\u5e93\u64cd\u4f5c\n    \/\/ ...\n    \n    \/\/ \u63d0\u4ea4\u4e8b\u52a1\n    transactionManager.commit(status);\n} catch (Exception ex) {\n    \/\/ \u56de\u6eda\u4e8b\u52a1\n    transactionManager.rollback(status);\n}\n\n<\/code><\/pre>\n<p>\u5728\u4f7f\u7528\u7f16\u7a0b\u5f0f\u4e8b\u52a1\u5904\u7406\u7684\u8fc7\u7a0b\u4e2d\uff0c\u5229\u7528 DefaultTransactionDefinition \u5bf9\u8c61\u6765\u6301\u6709\u4e8b\u52a1\u5904\u7406\u5c5e\u6027\u3002\u540c\u65f6\uff0c\u5728\u521b\u5efa\u4e8b\u52a1\u7684\u8fc7\u7a0b\u4e2d\u5f97\u5230\u4e00\u4e2a TransactionStatus \u5bf9\u8c61\uff0c\u7136\u540e\u901a\u8fc7\u76f4\u63a5\u8c03\u7528 transactionManager \u5bf9\u8c61 \u7684 commit() \u548c rollback()\u65b9\u6cd5 \u6765\u5b8c\u6210\u4e8b\u52a1\u5904\u7406\u3002<\/p>\n<h4>2.2 PlatformTransactionManager\u6838\u5fc3\u63a5\u53e3<\/h4>\n<p><img decoding=\"async\"   referrerpolicy=\"no-referrer\" src=\"https:\/\/s3.cn-north-1.jdcloud-oss.com\/shendengbucket1\/2024-01-25-19-188tAa0kIZhaw8vUd.png\" alt=\"\" title=\"\"><\/p>\n<p>PlatformTransactionManager\u662fSpring\u4e8b\u52a1\u7ba1\u7406\u7684\u6838\u5fc3\u63a5\u53e3\uff0c\u901a\u8fc7 PlatformTransactionManager \u63a5\u53e3\u8bbe\u8ba1\u4e86\u4e00\u7cfb\u5217\u4e0e\u4e8b\u52a1\u5904\u7406\u606f\u606f\u76f8\u5173\u7684\u63a5\u53e3\u65b9\u6cd5\uff0c\u5982 getTransaction()\u3001commit()\u3001rollback() \u8fd9\u4e9b\u548c\u4e8b\u52a1\u5904\u7406\u76f8\u5173\u7684\u7edf\u4e00\u63a5\u53e3\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u63a5\u53e3\u7684\u5b9e\u73b0\uff0c\u5f88\u5927\u4e00\u90e8\u5206\u662f\u7531 AbstractTransactionManager \u62bd\u8c61\u7c7b\u6765\u5b8c\u6210\u7684\u3002<\/p>\n<p>AbstractPlatformManager \u5c01\u88c5\u4e86 Spring \u4e8b\u52a1\u5904\u7406\u4e2d\u901a\u7528\u7684\u5904\u7406\u90e8\u5206\uff0c\u6bd4\u5982\u4e8b\u52a1\u7684\u521b\u5efa\u3001\u63d0\u4ea4\u3001\u56de\u6eda\uff0c\u4e8b\u52a1\u72b6\u6001\u548c\u4fe1\u606f\u7684\u5904\u7406\uff0c\u4e0e\u7ebf\u7a0b\u7684\u7ed1\u5b9a\u7b49\uff0c\u6709\u4e86\u8fd9\u4e9b\u901a\u7528\u5904\u7406\u7684\u652f\u6301\uff0c\u5bf9\u4e8e\u5177\u4f53\u7684\u4e8b\u52a1\u7ba1\u7406\u5668\u800c\u8a00\uff0c\u5b83\u4eec\u53ea\u9700\u8981\u5904\u7406\u548c\u5177\u4f53\u6570\u636e\u6e90\u76f8\u5173\u7684\u7ec4\u4ef6\u8bbe\u7f6e\u5c31\u53ef\u4ee5\u4e86\uff0c\u6bd4\u5982\u5728DataSourceTransactionManager\u4e2d\uff0c\u5c31\u53ea\u9700\u8981\u914d\u7f6e\u597d\u548cDataSource\u4e8b\u52a1\u5904\u7406\u76f8\u5173\u7684\u63a5\u53e3\u4ee5\u53ca\u76f8\u5173\u7684\u8bbe\u7f6e\u3002<\/p>\n<h4>2.3 \u4e8b\u52a1\u7684\u521b\u5efa<\/h4>\n<p>PlatformTransactionManager\u7684getTransaction()\u65b9\u6cd5\uff0c\u5c01\u88c5\u4e86\u5e95\u5c42\u4e8b\u52a1\u7684\u521b\u5efa\uff0c\u5e76\u751f\u6210\u4e00\u4e2a TransactionStatus\u5bf9\u8c61\u3002AbstractPlatformTransactionManager\u63d0\u4f9b\u4e86\u521b\u5efa\u4e8b\u52a1\u7684\u6a21\u677f\uff0c\u8fd9\u4e2a\u6a21\u677f\u4f1a\u88ab\u5177\u4f53\u7684\u4e8b\u52a1\u5904\u7406\u5668\u6240\u4f7f\u7528\u3002\u4ece\u4e0b\u9762\u7684\u4ee3\u7801\u4e2d\u53ef\u4ee5\u770b\u5230\uff0cAbstractPlatformTransactionManager\u4f1a\u6839\u636e\u4e8b\u52a1\u5c5e\u6027\u914d\u7f6e\u548c\u5f53\u524d\u8fdb\u7a0b\u7ed1\u5b9a\u7684\u4e8b\u52a1\u4fe1\u606f\uff0c\u5bf9\u4e8b\u52a1\u662f\u5426\u9700\u8981\u521b\u5efa\uff0c\u600e\u6837\u521b\u5efa \u8fdb\u884c\u4e00\u4e9b\u901a\u7528\u7684\u5904\u7406\uff0c\u7136\u540e\u628a\u4e8b\u52a1\u521b\u5efa\u7684\u5e95\u5c42\u5de5\u4f5c\u4ea4\u7ed9\u5177\u4f53\u7684\u4e8b\u52a1\u5904\u7406\u5668\u5b8c\u6210\uff0c\u5982\uff1aDataSourceTransactionManager\u3001HibernateTransactionManager\u3002<\/p>\n<pre><code>public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)\n        throws TransactionException {\n    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());\n    Object transaction = doGetTransaction();\n    boolean debugEnabled = logger.isDebugEnabled();\n    if (isExistingTransaction(transaction)) {\n        return handleExistingTransaction(def, transaction, debugEnabled);\n    }\n    if (def.getTimeout() &lt; TransactionDefinition.TIMEOUT_DEFAULT) {\n        throw new InvalidTimeoutException(&quot;Invalid transaction timeout&quot;, def.getTimeout());\n    }\n    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {\n        throw new IllegalTransactionStateException(\n                &quot;No existing transaction found for transaction marked with propagation 'mandatory'&quot;);\n    }\n    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||\n            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||\n            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {\n        SuspendedResourcesHolder suspendedResources = suspend(null);\n        if (debugEnabled) {\n            logger.debug(&quot;Creating new transaction with name [&quot; + def.getName() + &quot;]: &quot; + def);\n        }\n        try {\n            return startTransaction(def, transaction, false, debugEnabled, suspendedResources);\n        }\n        catch (RuntimeException | Error ex) {\n            resume(null, suspendedResources);\n            throw ex;\n        }\n    }\n    else {\n        if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT &amp;&amp; logger.isWarnEnabled()) {\n            logger.warn(&quot;Custom isolation level specified but no actual transaction initiated; &quot; +\n                    &quot;isolation level will effectively be ignored: &quot; + def);\n        }\n        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);\n        return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);\n    }\n}\n\nprivate TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {\n    boolean newSynchronization = this.getTransactionSynchronization() != SYNCHRONIZATION_NEVER;\n    DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);\n    this.doBegin(transaction, definition);\n    this.prepareSynchronization(status, definition);\n    return status;\n}\n\n<\/code><\/pre>\n<p>\u4e8b\u52a1\u521b\u5efa\u7684\u7ed3\u679c\u662f\u751f\u6210\u4e00\u4e2aTransactionStatus\u5bf9\u8c61\uff0c\u901a\u8fc7\u8fd9\u4e2a\u5bf9\u8c61\u6765\u4fdd\u5b58\u4e8b\u52a1\u5904\u7406\u9700\u8981\u7684\u57fa\u672c\u4fe1\u606f\uff0cTransactionStatus\u7684\u521b\u5efa\u8fc7\u7a0b\u5982\u4e0b\uff1a<\/p>\n<pre><code>protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {\n    boolean actualNewSynchronization = newSynchronization &amp;&amp; !TransactionSynchronizationManager.isSynchronizationActive();\n    return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.isReadOnly(), debug, suspendedResources);\n}\n\n<\/code><\/pre>\n<p>\u4ee5\u4e0a\u662f\u521b\u5efa\u4e00\u4e2a\u5168\u65b0\u4e8b\u52a1\u7684\u8fc7\u7a0b\uff0c\u8fd8\u6709\u53e6\u4e00\u79cd\u60c5\u51b5\u662f\uff1a\u5728\u521b\u5efa\u5f53\u524d\u4e8b\u52a1\u65f6\uff0c\u7ebf\u7a0b\u4e2d\u5df2\u7ecf\u6709\u4e8b\u52a1\u5b58\u5728\u4e86\u3002\u8fd9\u79cd\u60c5\u51b5\u4f1a\u6d89\u53ca\u4e8b\u52a1\u4f20\u64ad\u884c\u4e3a\u7684\u5904\u7406\u3002spring\u4e2d\u4e03\u79cd\u4e8b\u52a1\u4f20\u64ad\u884c\u4e3a\u5982\u4e0b\uff1a<\/p>\n<p>| \u4e8b\u52a1\u4f20\u64ad\u884c\u4e3a\u7c7b\u578b | \u8bf4\u660e |<br \/>| PROPAGATION_REQUIRED | \u5982\u679c\u5f53\u524d\u6ca1\u6709\u4e8b\u52a1\uff0c\u5c31\u65b0\u5efa\u4e00\u4e2a\u4e8b\u52a1\uff0c\u5982\u679c\u5df2\u7ecf\u5b58\u5728\u4e00\u4e2a\u4e8b\u52a1\u4e2d\uff0c\u52a0\u5165\u5230\u8fd9\u4e2a\u4e8b\u52a1\u4e2d\u3002\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u9009\u62e9\u3002 |<br \/>| PROPAGATION_SUPPORTS | \u652f\u6301\u5f53\u524d\u4e8b\u52a1\uff0c\u5982\u679c\u5f53\u524d\u6ca1\u6709\u4e8b\u52a1\uff0c\u5c31\u4ee5\u975e\u4e8b\u52a1\u65b9\u5f0f\u6267\u884c\u3002 |<br \/>| PROPAGATION_MANDATORY | \u4f7f\u7528\u5f53\u524d\u7684\u4e8b\u52a1\uff0c\u5982\u679c\u5f53\u524d\u6ca1\u6709\u4e8b\u52a1\uff0c\u5c31\u629b\u51fa\u5f02\u5e38\u3002 |<br \/>| PROPAGATION\/_REQUIRES\/_NEW | \u65b0\u5efa\u4e8b\u52a1\uff0c\u5982\u679c\u5f53\u524d\u5b58\u5728\u4e8b\u52a1\uff0c\u628a\u5f53\u524d\u4e8b\u52a1\u6302\u8d77\u3002 |<br \/>| PROPAGATION\/_NOT\/_SUPPORTED | \u4ee5\u975e\u4e8b\u52a1\u65b9\u5f0f\u6267\u884c\u64cd\u4f5c\uff0c\u5982\u679c\u5f53\u524d\u5b58\u5728\u4e8b\u52a1\uff0c\u5c31\u628a\u5f53\u524d\u4e8b\u52a1\u6302\u8d77\u3002 |<br \/>| PROPAGATION_NEVER | \u4ee5\u975e\u4e8b\u52a1\u65b9\u5f0f\u6267\u884c\uff0c\u5982\u679c\u5f53\u524d\u5b58\u5728\u4e8b\u52a1\uff0c\u5219\u629b\u51fa\u5f02\u5e38\u3002 |<br \/>| PROPAGATION_NESTED | \u5982\u679c\u5f53\u524d\u5b58\u5728\u4e8b\u52a1\uff0c\u5219\u5728\u5d4c\u5957\u4e8b\u52a1\u5185\u6267\u884c\u3002\u5982\u679c\u5f53\u524d\u6ca1\u6709\u4e8b\u52a1\uff0c\u5219\u6267\u884c\u4e0ePROPAGATION_REQUIRED\u7c7b\u4f3c\u7684\u64cd\u4f5c\u3002 |<\/p>\n<p>\u5982\u679c\u68c0\u6d4b\u5230\u5df2\u5b58\u5728\u4e8b\u52a1\uff0chandleExistingTransaction()\u65b9\u6cd5\u5c06\u6839\u636e\u4e0d\u540c\u7684\u4e8b\u52a1\u4f20\u64ad\u884c\u4e3a\u7c7b\u578b\u6267\u884c\u76f8\u5e94\u903b\u8f91\u3002<\/p>\n<p><strong>PROPAGATION_NEVER<\/strong><\/p>\n<p>\u5373\u5f53\u524d\u65b9\u6cd5\u9700\u8981\u5728\u975e\u4e8b\u52a1\u7684\u73af\u5883\u4e0b\u6267\u884c\uff0c\u5982\u679c\u6709\u4e8b\u52a1\u5b58\u5728\uff0c\u90a3\u4e48\u629b\u51fa\u5f02\u5e38\u3002<\/p>\n<pre><code>if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {\n    throw new IllegalTransactionStateException(\n            &quot;Existing transaction found for transaction marked with propagation 'never'&quot;);\n}\n\n<\/code><\/pre>\n<p><strong>PROPAGATION\/_NOT\/_SUPPORTED<\/strong><\/p>\n<p>\u4e0e\u524d\u8005\u7684\u533a\u522b\u5728\u4e8e\uff0c\u5982\u679c\u6709\u4e8b\u52a1\u5b58\u5728\uff0c\u90a3\u4e48\u5c06\u4e8b\u52a1\u6302\u8d77\uff0c\u800c\u4e0d\u662f\u629b\u51fa\u5f02\u5e38\u3002<\/p>\n<pre><code>if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {\n    Object suspendedResources = suspend(transaction);\n    boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);\n    return prepareTransactionStatus(\n        definition, null, false, newSynchronization, debugEnabled, suspendedResources);\n}\n\n<\/code><\/pre>\n<p><strong>PROPAGATION\/_REQUIRES\/_NEW<\/strong><\/p>\n<p>\u65b0\u5efa\u4e8b\u52a1\uff0c\u5982\u679c\u5f53\u524d\u5b58\u5728\u4e8b\u52a1\uff0c\u628a\u5f53\u524d\u4e8b\u52a1\u6302\u8d77\u3002<\/p>\n<pre><code>if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {\n    SuspendedResourcesHolder suspendedResources = suspend(transaction);\n    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);\n    DefaultTransactionStatus status = newTransactionStatus(\n            definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);\n    doBegin(transaction, definition);\n    prepareSynchronization(status, definition);\n    return status;\n}\n\n<\/code><\/pre>\n<p><strong>PROPAGATION_NESTED<\/strong><\/p>\n<p>\u5f00\u59cb\u4e00\u4e2a &#8220;\u5d4c\u5957\u7684&#8221; \u4e8b\u52a1, \u5b83\u662f\u5df2\u7ecf\u5b58\u5728\u4e8b\u52a1\u7684\u4e00\u4e2a\u771f\u6b63\u7684\u5b50\u4e8b\u52a1. \u5d4c\u5957\u4e8b\u52a1\u5f00\u59cb\u6267\u884c\u65f6, \u5b83\u5c06\u53d6\u5f97\u4e00\u4e2a savepoint. \u5982\u679c\u8fd9\u4e2a\u5d4c\u5957\u4e8b\u52a1\u5931\u8d25, \u6211\u4eec\u5c06\u56de\u6eda\u5230\u6b64 savepoint. \u5d4c\u5957\u4e8b\u52a1\u662f\u5916\u90e8\u4e8b\u52a1\u7684\u4e00\u90e8\u5206, \u53ea\u6709\u5916\u90e8\u4e8b\u52a1\u7ed3\u675f\u540e\u5b83\u624d\u4f1a\u88ab\u63d0\u4ea4\u3002<\/p>\n<pre><code>if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {\n    if (useSavepointForNestedTransaction()) {\n        DefaultTransactionStatus status = newTransactionStatus(\n                definition, transaction, false, false, true, debugEnabled, null);\n        this.transactionExecutionListeners.forEach(listener -&gt; listener.beforeBegin(status));\n        try {\n            status.createAndHoldSavepoint();\n        }\n        catch (RuntimeException | Error ex) {\n            this.transactionExecutionListeners.forEach(listener -&gt; listener.afterBegin(status, ex));\n            throw ex;\n        }\n        this.transactionExecutionListeners.forEach(listener -&gt; listener.afterBegin(status, null));\n        return status;\n    }\n    else {\n        return startTransaction(definition, transaction, true, debugEnabled, null);\n    }\n}\n\n<\/code><\/pre>\n<h4>2.4 \u4e8b\u52a1\u6302\u8d77<\/h4>\n<p>\u4e8b\u52a1\u6302\u8d77\u5728AbstractTransactionManager.suspend()\u4e2d\u5904\u7406\uff0c\u8be5\u65b9\u6cd5\u5185\u90e8\u5c06\u8c03\u7528\u5177\u4f53\u4e8b\u52a1\u7ba1\u7406\u5668\u7684doSuspend()\u65b9\u6cd5\u3002\u4ee5DataSourceTransactionManager\u4e3a\u4f8b\uff0c\u5c06ConnectionHolder\u8bbe\u4e3anull\uff0c\u56e0\u4e3a\u4e00\u4e2aConnectionHolder\u5bf9\u8c61\u5c31\u4ee3\u8868\u4e86\u4e00\u4e2a\u6570\u636e\u5e93\u8fde\u63a5\uff0c\u5c06ConnectionHolder\u8bbe\u4e3anull\u5c31\u610f\u5473\u7740\u6211\u4eec\u4e0b\u6b21\u8981\u4f7f\u7528\u8fde\u63a5\u65f6\uff0c\u5c06\u91cd\u65b0\u4ece\u8fde\u63a5\u6c60\u83b7\u53d6\u3002<\/p>\n<pre><code>protected Object doSuspend(Object transaction) {\n    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;\n    txObject.setConnectionHolder(null);\n    return TransactionSynchronizationManager.unbindResource(obtainDataSource());\n}\n\n<\/code><\/pre>\n<p>unbindResource()\u65b9\u6cd5\u6700\u7ec8\u4f1a\u8c03\u7528TransactionSynchronizationManager.doUnbindResource()\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u79fb\u9664\u5f53\u524d\u7ebf\u7a0b\u4e0e\u4e8b\u52a1\u5bf9\u8c61\u7684\u7ed1\u5b9a\u3002<\/p>\n<pre><code>private static Object doUnbindResource(Object actualKey) {\n    Map&lt;Object, Object&gt; map = resources.get();\n    if (map == null) {\n        return null;\n    }\n    Object value = map.remove(actualKey);\n    if (map.isEmpty()) {\n        resources.remove();\n    }\n    if (value instanceof ResourceHolder resourceHolder &amp;&amp; resourceHolder.isVoid()) {\n        value = null;\n    }\n    return value;\n}\n\n<\/code><\/pre>\n<p>\u800c\u88ab\u6302\u8d77\u7684\u4e8b\u52a1\u7684\u5404\u79cd\u72b6\u6001\u6700\u7ec8\u4f1a\u4fdd\u5b58\u5728TransactionStatus\u5bf9\u8c61\u4e2d\u3002<\/p>\n<h4>2.5 \u4e8b\u52a1\u63d0\u4ea4&#038;\u56de\u6eda<\/h4>\n<p>\u4e3b\u8981\u662f\u5bf9jdbc\u7684\u5c01\u88c5\u3001\u6e90\u7801\u903b\u8f91\u8f83\u6e05\u6670\uff0c\u4e0d\u5c55\u5f00\u7ec6\u8bf4\u3002<\/p>\n<h2>3\u3001\u58f0\u660e\u5f0f\u4e8b\u52a1<\/h2>\n<p>\u5176\u5e95\u5c42\u5efa\u7acb\u5728 AOP \u7684\u57fa\u7840\u4e4b\u4e0a\uff0c\u5bf9\u65b9\u6cd5\u524d\u540e\u8fdb\u884c\u62e6\u622a\uff0c\u7136\u540e\u5728\u76ee\u6807\u65b9\u6cd5\u5f00\u59cb\u4e4b\u524d\u521b\u5efa\u6216\u8005\u52a0\u5165\u4e00\u4e2a\u4e8b\u52a1\uff0c\u5728\u6267\u884c\u5b8c\u76ee\u6807\u65b9\u6cd5\u4e4b\u540e\u6839\u636e\u6267\u884c\u60c5\u51b5\u63d0\u4ea4\u6216\u8005\u56de\u6eda\u4e8b\u52a1\u3002\u901a\u8fc7\u58f0\u660e\u5f0f\u4e8b\u7269\uff0c\u65e0\u9700\u5728\u4e1a\u52a1\u903b\u8f91\u4ee3\u7801\u4e2d\u63ba\u6742\u4e8b\u52a1\u7ba1\u7406\u7684\u4ee3\u7801\uff0c\u53ea\u9700\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u505a\u76f8\u5173\u7684\u4e8b\u52a1\u89c4\u5219\u58f0\u660e\uff08\u6216\u901a\u8fc7\u7b49\u4ef7\u7684\u57fa\u4e8e\u6807\u6ce8\u7684\u65b9\u5f0f\uff09\uff0c\u4fbf\u53ef\u4ee5\u5c06\u4e8b\u52a1\u89c4\u5219\u5e94\u7528\u5230\u4e1a\u52a1\u903b\u8f91\u4e2d\u3002<\/p>\n<h4>3.1 \u4f7f\u7528\u793a\u4f8b<\/h4>\n<p>\u914d\u7f6e\uff1a<\/p>\n<pre><code>&lt;bean id=&quot;dataSource&quot; class=&quot;com.zaxxer.hikari.HikariDataSource&quot;&gt;\n    &lt;property name=&quot;driverClassName&quot; value=&quot;${jdbc.driverClassName}&quot; \/&gt;\n    &lt;property name=&quot;url&quot; value=&quot;${jdbc.url}&quot; \/&gt;\n    &lt;property name=&quot;username&quot; value=&quot;${jdbc.username}&quot; \/&gt;\n    &lt;property name=&quot;password&quot; value=&quot;${jdbc.password}&quot; \/&gt;\n&lt;\/bean&gt;\n&lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;&gt;\n    &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;\/&gt;\n&lt;\/bean&gt;\n&lt;tx:annotation-driven transaction-manager=&quot;transactionManager&quot;\/&gt;\n\n<\/code><\/pre>\n<p>\u4ee3\u7801\uff1a<\/p>\n<pre><code>@Transactional\npublic void addOrder() {\n    \/\/ \u6267\u884c\u6570\u636e\u5e93\u64cd\u4f5c\n}\n\n<\/code><\/pre>\n<h4>3.2 \u81ea\u5b9a\u4e49\u6807\u7b7e\u89e3\u6790<\/h4>\n<p>\u5148\u4ece\u914d\u7f6e\u6587\u4ef6\u5f00\u59cb\u5165\u624b\uff0c\u627e\u5230\u5904\u7406annotation-driven\u6807\u7b7e\u7684\u7c7bTxNamespaceHandler\u3002TxNamespaceHandler\u5b9e\u73b0\u4e86NamespaceHandler\u63a5\u53e3\uff0c\u5b9a\u4e49\u4e86\u5982\u4f55\u89e3\u6790\u548c\u5904\u7406\u81ea\u5b9a\u4e49XML\u6807\u7b7e\u3002<\/p>\n<pre><code>@Override\npublic void init() {\n    registerBeanDefinitionParser(&quot;advice&quot;, new TxAdviceBeanDefinitionParser());\n    registerBeanDefinitionParser(&quot;annotation-driven&quot;, new AnnotationDrivenBeanDefinitionParser());\n    registerBeanDefinitionParser(&quot;jta-transaction-manager&quot;, new JtaTransactionManagerBeanDefinitionParser());\n}\n\n<\/code><\/pre>\n<p>AnnotationDrivenBeanDefinitionParser\u91cc\u7684parse()\u65b9\u6cd5\uff0c\u5bf9XML\u6807\u7b7eannotation-driven\u8fdb\u884c\u89e3\u6790\u3002<\/p>\n<pre><code>@Override\npublic BeanDefinition parse(Element element, ParserContext parserContext) {\n    registerTransactionalEventListenerFactory(parserContext);\n    String mode = element.getAttribute(&quot;mode&quot;);\n    if (&quot;aspectj&quot;.equals(mode)) {\n        \/\/ mode=&quot;aspectj&quot;\n        registerTransactionAspect(element, parserContext);\n        if (ClassUtils.isPresent(&quot;jakarta.transaction.Transactional&quot;, getClass().getClassLoader())) {\n            registerJtaTransactionAspect(element, parserContext);\n        }\n    }\n    else {\n        \/\/ mode=&quot;proxy&quot;\n        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);\n    }\n    return null;\n}\n\n<\/code><\/pre>\n<p>\u4ee5\u9ed8\u8ba4mode\u914d\u7f6e\u4e3a\u4f8b\uff0c\u6267\u884cconfigureAutoProxyCreator()\u65b9\u6cd5\uff0c\u5c06\u5728Spring\u5bb9\u5668\u4e2d\u6ce8\u518c\u4e863\u4e2abean:<\/p>\n<p>BeanFactoryTransactionAttributeSourceAdvisor\u3001TransactionInterceptor\u3001AnnotationTransactionAttributeSource\u3002\u540c\u65f6\u4f1a\u5c06TransactionInterceptor\u7684BeanName\u4f20\u5165\u5230Advisor\u4e2d\uff0c\u7136\u540e\u5c06AnnotationTransactionAttributeSource\u8fd9\u4e2aBean\u6ce8\u5165\u5230Advisor\u4e2d\u3002\u4e4b\u540e\u52a8\u6001\u4ee3\u7406\u7684\u65f6\u5019\u4f1a\u4f7f\u7528\u8fd9\u4e2aAdvisor\u53bb\u5bfb\u627e\u6bcf\u4e2aBean\u662f\u5426\u9700\u8981\u52a8\u6001\u4ee3\u7406\u3002<\/p>\n<pre><code>\/\/ Create the TransactionAttributeSourceAdvisor definition.\nRootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);\nadvisorDef.setSource(eleSource);\nadvisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\nadvisorDef.getPropertyValues().add(&quot;transactionAttributeSource&quot;, new RuntimeBeanReference(sourceName));\nadvisorDef.getPropertyValues().add(&quot;adviceBeanName&quot;, interceptorName);\nif (element.hasAttribute(&quot;order&quot;)) {\n    advisorDef.getPropertyValues().add(&quot;order&quot;, element.getAttribute(&quot;order&quot;));\n}\nparserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);\n\nCompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);\ncompositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));\ncompositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));\ncompositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));\nparserContext.registerComponent(compositeDef);\n\n<\/code><\/pre>\n<h4>3.3 Advisor<\/h4>\n<p>\u56de\u987eAOP\u7528\u6cd5\uff0cAdvisor\u53ef\u7528\u4e8e\u5b9a\u4e49\u4e00\u4e2a\u5207\u9762\uff0c\u5b83\u5305\u542b\u5207\u70b9\uff08Pointcut\uff09\u548c\u901a\u77e5\uff08Advice\uff09\uff0c\u7528\u4e8e\u5728\u7279\u5b9a\u7684\u8fde\u63a5\u70b9\u4e0a\u6267\u884c\u7279\u5b9a\u7684\u64cd\u4f5c\u3002spring\u4e8b\u52a1\u5b9e\u73b0\u4e86\u4e00\u4e2aAdvisor: BeanFactoryTransactionAttributeSourceAdvisor\u3002<\/p>\n<pre><code>public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {\n\n    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();\n\n    public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {\n        this.pointcut.setTransactionAttributeSource(transactionAttributeSource);\n    }\n\n    public void setClassFilter(ClassFilter classFilter) {\n        this.pointcut.setClassFilter(classFilter);\n    }\n\n    @Override\n    public Pointcut getPointcut() {\n        return this.pointcut;\n    }\n}\n\n<\/code><\/pre>\n<p>BeanFactoryTransactionAttributeSourceAdvisor\u5176\u5b9e\u662f\u4e00\u4e2aPointcutAdvisor\uff0c\u662f\u5426\u5339\u914d\u5230\u5207\u5165\u70b9\u53d6\u51b3\u4e8ePointcut\u3002Pointcut\u7684\u6838\u5fc3\u5728\u4e8e\u5176ClassFilter\u548cMethodMatcher\u3002<\/p>\n<p><strong>ClassFilter:<\/strong><\/p>\n<p>TransactionAttributeSourcePointcut\u5185\u90e8\u79c1\u6709\u7c7b TransactionAttributeSourceClassFilter\uff0c\u5b9e\u73b0\u4e86Spring\u6846\u67b6\u4e2d\u7684ClassFilter\u63a5\u53e3\u3002\u5728matches\u65b9\u6cd5\u4e2d\uff0c\u5b83\u9996\u5148\u68c0\u67e5\u4f20\u5165\u7684\u7c7bclazz \u5426\u4e3aTransactionalProxy\u3001TransactionManager\u6216PersistenceExceptionTranslator\u7684\u5b50\u7c7b\uff0c\u5982\u679c\u4e0d\u662f\uff0c\u5219\u83b7\u53d6\u5f53\u524d\u7684 TransactionAttributeSource \u5e76\u68c0\u67e5\u5176\u662f\u5426\u5141\u8bb8\u8be5\u7c7b\u4f5c\u4e3a\u5019\u9009\u7c7b\u3002<\/p>\n<pre><code>private class TransactionAttributeSourceClassFilter implements ClassFilter {\n    @Override\n    public boolean matches(Class&lt;?&gt; clazz) {\n        if (TransactionalProxy.class.isAssignableFrom(clazz) ||\n                TransactionManager.class.isAssignableFrom(clazz) ||\n                PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {\n            return false;\n        }\n        return (transactionAttributeSource == null || transactionAttributeSource.isCandidateClass(clazz));\n    }\n}\n\n<\/code><\/pre>\n<p><strong>MethodMatcher:<\/strong><\/p>\n<p>TransactionAttributeSourcePointcut.matches:<\/p>\n<pre><code>@Override\npublic boolean matches(Method method, Class&lt;?&gt; targetClass) {\n    return (this.transactionAttributeSource == null ||\n            this.transactionAttributeSource.getTransactionAttribute(method, targetClass) != null);\n}\n\n<\/code><\/pre>\n<p>getTransactionAttribute()\u65b9\u6cd5\u6700\u7ec8\u4f1a\u8c03\u7528\u81f3AbstractFallbackTransactionAttributeSource.computeTransactionAttribute()\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u5148\u53bb\u65b9\u6cd5\u4e0a\u67e5\u627e\u662f\u5426\u6709\u76f8\u5e94\u7684\u4e8b\u52a1\u6ce8\u89e3(\u6bd4\u5982@Transactional)\uff0c\u5982\u679c\u6ca1\u6709\uff0c\u90a3\u4e48\u518d\u53bb\u7c7b\u4e0a\u67e5\u627e\u3002<\/p>\n<pre><code>protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class&lt;?&gt; targetClass) {\n    \/\/ Don't allow non-public methods, as configured.\n    if (allowPublicMethodsOnly() &amp;&amp; !Modifier.isPublic(method.getModifiers())) {\n        return null;\n    }\n\n    \/\/ The method may be on an interface, but we need attributes from the target class.\n    \/\/ If the target class is null, the method will be unchanged.\n    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);\n\n    \/\/ First try is the method in the target class.\n    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);\n    if (txAttr != null) {\n        return txAttr;\n    }\n\n    \/\/ Second try is the transaction attribute on the target class.\n    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());\n    if (txAttr != null &amp;&amp; ClassUtils.isUserLevelMethod(method)) {\n        return txAttr;\n    }\n\n    if (specificMethod != method) {\n        \/\/ Fallback is to look at the original method.\n        txAttr = findTransactionAttribute(method);\n        if (txAttr != null) {\n            return txAttr;\n        }\n        \/\/ Last fallback is the class of the original method.\n        txAttr = findTransactionAttribute(method.getDeclaringClass());\n        if (txAttr != null &amp;&amp; ClassUtils.isUserLevelMethod(method)) {\n            return txAttr;\n        }\n    }\n\n    return null;\n}\n\n<\/code><\/pre>\n<h4>3.4 TransactionInterceptor<\/h4>\n<p>TransactionInterceptor\u662fspring\u4e8b\u52a1\u63d0\u4f9b\u7684AOP\u62e6\u622a\u5668\uff0c\u5b9e\u73b0\u4e86AOP Alliance\u7684MethodInterceptor\u63a5\u53e3\uff0c\u662f\u4e00\u79cd\u901a\u77e5\uff08advice\uff09\u3002\u5176\u53ef\u4ee5\u7528\u4e8e\u5728\u65b9\u6cd5\u8c03\u7528\u524d\u540e\u8fdb\u884c\u4e8b\u52a1\u7ba1\u7406\u3002<\/p>\n<pre><code>@Override\n@Nullable\npublic Object invoke(MethodInvocation invocation) throws Throwable {\n    \/\/ Work out the target class: may be {@code null}.\n    \/\/ The TransactionAttributeSource should be passed the target class\n    \/\/ as well as the method, which may be from an interface.\n    Class&lt;?&gt; targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);\n\n    \/\/ Adapt to TransactionAspectSupport's invokeWithinTransaction...\n    return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {\n        @Override\n        @Nullable\n        public Object proceedWithInvocation() throws Throwable {\n            return invocation.proceed();\n        }\n        @Override\n        public Object getTarget() {\n            return invocation.getThis();\n        }\n        @Override\n        public Object[] getArguments() {\n            return invocation.getArguments();\n        }\n    });\n}\n\n<\/code><\/pre>\n<p>invokeWithinTransaction()\u65b9\u6cd5\u4f1a\u6839\u636e\u76ee\u6807\u65b9\u6cd5\u4e0a\u7684\u4e8b\u52a1\u914d\u7f6e\uff0c\u6765\u51b3\u5b9a\u662f\u5f00\u542f\u65b0\u4e8b\u52a1\u3001\u52a0\u5165\u5df2\u6709\u4e8b\u52a1\uff0c\u8fd8\u662f\u76f4\u63a5\u6267\u884c\u903b\u8f91\uff08\u5982\u679c\u6ca1\u6709\u4e8b\u52a1\uff09\u3002\u5176\u4ee3\u7801\u7b80\u5316\u5982\u4e0b(\u4ec5\u4fdd\u7559PlatformTransactionManager\u90e8\u5206)\uff1a<\/p>\n<pre><code>protected Object invokeWithinTransaction(Method method, @Nullable Class&lt;?&gt; targetClass, final InvocationCallback invocation) {\n    \/\/ If the transaction attribute is null, the method is non-transactional.\n    final TransactionAttribute txAttr = getTransactionAttributeSource()\n        .getTransactionAttribute(method, targetClass);\n    final PlatformTransactionManager tm = determineTransactionManager(txAttr);\n    final String joinpointIdentification = methodIdentification(method, targetClass);\n    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {\n        \/\/ Standard transaction demarcation with getTransaction and commit\/rollback calls.\n        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);\n        ObjectretVal = null;\n        try {\n            \/\/ This is an around advice: Invoke the next interceptor in the chain.\n            \/\/ This will normally result in a target object being invoked.\n            retVal = invocation.proceedWithInvocation();\n        } catch (Throwableex) {\n            \/\/ target invocation exception\n            completeTransactionAfterThrowing(txInfo, ex);\n            throwex;\n        } finally {\n            cleanupTransactionInfo(txInfo);\n        }\n        commitTransactionAfterReturning(txInfo);\n        returnretVal;\n    }\n}\n\n<\/code><\/pre>\n<p>\u4f5c\u8005\uff1a\u4eac\u4e1c\u96f6\u552e \u8303\u9521\u519b<\/p>\n<p>\u6765\u6e90\uff1a\u4eac\u4e1c\u4e91\u5f00\u53d1\u8005\u793e\u533a \u8f6c\u8f7d\u8bf7\u6ce8\u660e\u6765\u6e90<\/p>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000044636339\">https:\/\/segmentfault.com\/a\/1190000044636339<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1\u3001\u5f15\u8a00 spring\u7684spring-tx\u6a21\u5757\u63d0\u4f9b\u4e86\u5bf9\u4e8b\u52a1\u7ba1\u7406\u652f\u6301\uff0c\u4f7f\u7528spring\u4e8b\u52a1\u53ef\u4ee5\u8ba9\u6211\u4eec\u4ece\u590d\u6742\u7684\u4e8b\u52a1 [&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-10008361","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\/10008361","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=10008361"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10008361\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10008361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10008361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10008361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}