ホームページ  >  記事  >  データベース  >  Spring トランザクション分離レベル、伝播動作、および spring+mybatis+atomikos により分散トランザクション管理が実現されます。

Spring トランザクション分離レベル、伝播動作、および spring+mybatis+atomikos により分散トランザクション管理が実現されます。

坏嘻嘻
坏嘻嘻オリジナル
2018-09-15 11:04:582390ブラウズ

この記事の内容は、分散トランザクション管理の Spring トランザクション分離レベル、伝播動作、および Spring mybatis atomikos の実装に関するもので、必要な方は参考にしていただければ幸いです。ヘルプ。

1. トランザクションの定義: トランザクションは、複数の操作単位の集合を指し、全体として分割できません。操作が失敗するか、すべてが成功します。 4 つの原則 (ACID) に従う必要があります。

  1. アトミック性 : つまり、トランザクションは分割できない最小の作業単位であり、トランザクション内のすべての操作は完了するか、何も行われないかのどちらかです。

  2. #一貫性 : トランザクションが実行される前、データベース内のデータは正しい状態にあり、トランザクション後もデータベース内のデータは依然として正しい状態である必要があります。完了している、つまり、銀行振込などのデータ整合性の制約が破壊されていない場合、A のお金が B に送金される必要があり、A のお金が送金されることは決してありません。は転送されますが、B はそれを受信しません。そうしないと、データベース内のデータが不整合 (不正) な状態になります。

  3. 分離 : 同時トランザクションの実行は相互に影響しません。1 つのトランザクション内の操作は他のトランザクションに影響を与えません。これには、分離を指定するトランザクション分離レベルが必要です。 ;

  4. 耐久性 (耐久性) : トランザクションが正常に実行されると、データベース データへの変更は永続的になる必要があり、データの不整合や損失が発生する可能性があります。たとえば、システム障害や停電などです。

#2. トランザクションの種類

    データベースはローカル トランザクションとグローバル トランザクションに分かれています
    ローカル トランザクション: データベースから独立した通常のトランザクション。データベース上での操作の ACID を保証できます。
  • 分散トランザクション: 2 つ以上のデータベース ソースが関与するトランザクション、つまり、同じタイプまたは異種タイプの複数のデータベースにまたがるトランザクション (各データベースのローカル トランザクションで構成されます)。正式なトランザクションの機能は、トランザクションが複数のデータベースにまたがることができるように、これらのローカル トランザクションのすべての操作の ACID を保証することです。
Java トランザクション タイプは JDBC トランザクションと JTA トランザクションに分割されます。
    • JDBC トランザクション: これは、前述のデータベース トランザクションのローカル トランザクションであり、
    • connection

      オブジェクトを通じて制御および管理されます。

    • JTA トランザクション: JTA は、Java EE データベース トランザクション仕様である Java トランザクション API (Java Transaction API) を指します。
    • はトランザクション管理インターフェイスのみを提供します。これはアプリケーション サーバー ベンダー (WebSphere Application Server など) が提供する実装によって制御されます。JTA トランザクションは JDBC よりも強力であり、

      分散トランザクションをサポートします。

      プログラムされているかどうかに応じて、宣言的トランザクションとプログラム的トランザクションに分けられます。 http://blog.csdn.net/liaohaojian/article/details を参照してください。 /70139151
  • 宣言型トランザクション: XML 構成またはアノテーションを通じて実装されます。
    • プログラムによるトランザクション: ビジネス ロジックが必要な場合、より細かい粒度でプログラミング コードを通じて実装されます。

    • 3. Spring トランザクション分離レベル: Spring には 5 つの分離レベルがあり、TransactionDefinition インターフェイスで定義されます。ソース コードを見ると、デフォルトのisolation_default (基礎となるデータベースのデフォルト レベル) と、他の 4 つの分離レベルがデータベース分離レベルと一致していることがわかります。

      ISOLATION_DEFAULT
    1. : データベース管理者が設定したものに関係なく、基礎となるデータベースのデフォルトの分離レベルを使用します。 ISOLATION_READ_UNCOMMITTED (非コミット読み取り): 最も低い分離レベル。トランザクションがコミットされる前に、他のトランザクションによって読み取ることができます (ファントム読み取り、ダーティー読み取り、および非反復読み取りが発生します) )

    2. ISOLATION_READ_COMMITTED (読み取りコミット) : トランザクションは、送信された後は他のトランザクションによってのみ読み取ることができます (この分離レベルでは、他のトランザクションによるデータの読み取りが禁止されます)コミットされていないトランザクションなので、依然としてファントム読み取りと反復不可能な読み取りが発生します)、SQL サーバーのデフォルト レベル

    3. ISOLATION_REPEATABLE_READ (反復可能な読み取り) : 反復可能な読み取り、複数の読み取りが同時に実行されます。 データが生成されると、その値はトランザクションの開始時の内容と一致し、コミットされていないデータを他のトランザクションから読み取ることは禁止されます (この分離により、基本的にダーティ リードと反復不可能な読み取り (変更に重点が置かれています)、ただしファントム読み取りは発生します) (追加と削除に重点が置かれています)) (MySql のデフォルト レベル、変更はトランザクション分離レベル レベルの設定を通じて行うことができます

      )
    4. ISOLATION_SERIALIZABLE (シリアル化): 最も高価で信頼性の高い分離レベル (この分離レベルにより、ダーティ リード、非反復読み取り、ファントム リードを防止できます)

      1. 更新の喪失: 2 つのトランザクションが同時にデータ行を更新すると、最後のトランザクションの更新によって最初のトランザクションの更新が上書きされ、更新されたデータが失われます。最初のトランザクションによるこれは、ロックの欠如が原因です。

      2. ファントム読み取り: 同じトランザクション操作中に、異なる時間に同じデータが複数回読み取られます。期間が異なり、読み込んだ内容が不一致になります(通常、行数が多少前後します)。

      3. ダーティ リード: トランザクションは、言及されていない別のトランザクションの内容を読み取ります。これはダーティ リードです。

      4. 反復不可能な読み取り: 同じトランザクション内で、複数回読み取られた内容に一貫性がありません (通常、行数は変わりませんが、内容は変わります)。

    ファントム読み取りと反復不能読み取りの違い: ファントム読み取りの焦点は 挿入と削除です。つまり、2 番目のクエリはデータが最初のものよりも優れているということ クエリ データが少なくなったり増えたりして、人々に錯覚を与えます。反復不可能な読み取りの重要なポイントは、変更です。つまり、2 番目のクエリでは、クエリの結果が判明します。最初のクエリ結果と矛盾しています。つまり、最初の結果は再現できません。

    データベース分離レベルが高くなると、実行コストが高くなり、同時実行能力が低下するため、実際のプロジェクトを開発および使用する際には、同時実行パフォーマンスを考慮する必要があります。 ##通常は submit 読み取り分離 レベルを使用します。これにより、更新の損失やダーティ読み取りを回避できますが、非反復読み取りやファントム読み取りは回避できませんが、 悲観的ロックまたは楽観的ロック を使用できます。可能な場合はこれらの問題を解決します。

    4. 通信動作: 7 つの主要な通信動作があり、これらも TransactionDefinition インターフェイスで定義されています。

    1. PROPAGATION_REQUIRED: 現在のトランザクションをサポートします。現在のトランザクションがない場合は、新しいトランザクションを作成します。

    2. PROPAGATION_SUPPORTS: 現在のトランザクションをサポートします。現在トランザクションがない場合は、非トランザクションで実行されます (ソース コードにメモがあります)。は明確ではないので、後回しにしておきます)後で検討します)。

    3. PROPAGATION_MANDATORY: 現在のトランザクションをサポートします。現在のトランザクションがない場合、例外がスローされます (既存のトランザクションで実行する必要があります)。ビジネス メソッドは、独自のトランザクションを独自に開始することはできません)。

    4. PROPAGATION_REQUIRES_NEW: 現在トランザクションがある場合は、常に新しいトランザクションを作成します。元のトランザクションは一時停止されます。

    5. PROPAGATION_NOT_SUPPORTED: 現在のトランザクションはサポートされていないため、常に非トランザクション方式で実行されます。 現在のトランザクションが存在する場合、トランザクションは一時停止されます。 。

    6. PROPAGATION_NEVER: 現在のトランザクションはサポートされていません。現在のトランザクションが存在する場合、例外がスローされます。

    7. PROPAGATION_NESTED: 現在のトランザクションが存在する場合は、ネストされたトランザクションで実行されます。 現在のトランザクションが存在しない場合は、次のような操作が実行されます。 PROPAGATION_REQUIRED (注: JDBC に適用される場合、JDBC 3.0 以降のドライバーにのみ適用されます)。

    #5.Spring トランザクション サポート

    1.spring は、サポートする多くの組み込みトランザクション マネージャーを提供します。さまざまなデータソース。 3 つの共通カテゴリがあります

    • DataSourceTransactionManager

      : org.springframework.jdbc.datasource パッケージの下には、データ ソース トランザクション管理クラス。JDBC および Mybatis フレームワークのトランザクション管理に使用される限り、単一の javax.sql.DataSource データ ソースのトランザクション管理を提供します。

    • HibernateTransactionManager

      : org.springframework.orm.hibernate3 パッケージの下で、データ ソース トランザクション管理クラスは、統合のための単一の org.hibernate.SessionFactory トランザクションのサポートを提供します。 Hibernate フレームワークでのトランザクション管理。 注: このトランザクション マネージャーは Hibernate3 バージョンのみをサポートし、Spring3.0 バージョンは Hibernate 3.2 バージョンのみをサポートします。 ##JtaTransactionManager: org.springframework.transaction.jta パッケージにあり、分散トランザクション管理のサポートを提供し、トランザクション管理を Java EE アプリケーション サーバーに委任するか、ローカル JTA トランザクションをカスタマイズします。マネージャー、アプリケーションにネストされています。

    • 組み込みトランザクション マネージャーはすべて、抽象クラス AbstractPlatformTransactionManager を継承し、AbstractPlatformTransactionManager はインターフェイス PlatformTransactionManager を継承します。Spring フレームワークのトランザクション管理サポートの中核トランザクション マネージャーです。 要約: さまざまなデータ アクセス フレームワークに対して、戦略インターフェイス PlatformTransactionManager が実装され、複数のデータ アクセス フレームワークのトランザクション管理をサポートします。 PlatformTransactionManager インターフェースは次のように定義されています
      TransactionStatus インターフェイスは次のように定義されます:

      public interface TransactionStatus extends SavepointManager {  
             boolean isNewTransaction();  //返回当前事务是否是新的事务
             boolean hasSavepoint();  //返回当前事务是否有保存点
             void setRollbackOnly();  //设置事务回滚
             boolean isRollbackOnly();  //设置当前事务是否应该回滚
             void flush();  //用于刷新底层会话中的修改到数据库,一般用于刷新如Hibernate/JPA的会话,可能对如JDBC类型的事务无任何影响;
             boolean isCompleted();  //返回事务是否完成
      }

      2. Spring 分散トランザクション構成

      • アプリケーション サーバー (Tomcat など) の JNDI データ ソースを参照します。 JTA トランザクションを間接的に実装する 管理は、アプリケーション サーバー

      • に依存して、JOTM (公式 Web サイト: http://jotm.objectweb.org/) と Amitikos (公式 Web サイト: https: //www.atomikos.com/ ) JTA トランザクション管理を提供します (アプリケーション サーバーのサポートはありません。単体テストによく使用されます)

      • アプリケーション サーバー固有のトランザクション マネージャーを使用して、次の高度な機能を使用します。 JTA トランザクション (Weblogic、Websphere)

      1) アプリケーション サーバー (Tomcat など) の JNDI データ ソースを参照して、JTA トランザクション管理を間接的に実装します。

      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:jee="http://www.springframework.org/schema/jee"
          xsi:schemaLocation="
             http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
             http://www.springframework.org/schema/jee
             http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
       <!-- JNDI数据源 -->
        <jee:jndi-lookup id="dataSource" jndi-name="jdbc/test"/>
          <!-- JTA事务管理器  -->
        	<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        		<!--transactionManagerName指定JTA事务管理器的JNDI名字,从而将事务管理委托给该事务管理器  -->
          	<property name="transactionManagerName" value="java:comp/TransactionManager"/>
        	</bean>
      </beans>

      2) Atomikos を使用して分散トランザクション管理を実装します。構成は次のとおりです:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      	xmlns:p="http://www.springframework.org/schema/p"
      	xmlns:aop="http://www.springframework.org/schema/aop"	
      	xmlns:tx="http://www.springframework.org/schema/tx"
      	xmlns:context="http://www.springframework.org/schema/context"
          xmlns:task="http://www.springframework.org/schema/task"
      	xsi:schemaLocation="http://www.springframework.org/schema/beans 
      	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      	http://www.springframework.org/schema/context 
      	http://www.springframework.org/schema/context/spring-context-3.0.xsd
      	http://www.springframework.org/schema/tx
      	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
      	http://www.springframework.org/schema/task
      	http://www.springframework.org/schema/task/spring-task-3.0.xsd
      	http://www.springframework.org/schema/aop
      	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
      	>  
      	<context:component-scan base-package="com.suicai.*.service.impl" />
      	<context:component-scan base-package="com.suicai.util" />
          <!-- 此方法加载的配置文件仅仅在xml中使用,但是工具类都采用注解的方式 -->
      	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      		<property name="location" value="classpath:conn.properties" />
      	</bean>
      	<!-- 仅仅支持注解不支持在xml配置中使用properties文件  在类中可以使用SPEL表达式来加载相应的值 -->
      	<bean id="temp" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
      		<property name="locations">
      			<array>
      				<value>classpath:public.properties</value>
      			</array>
      		</property>
      	</bean>
      	<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"  destroy-method="close" abstract="true"> 
              <property name="borrowConnectionTimeout" value="60"/>  <!--获取连接失败重新获等待最大时间,在这个时间内如果有可用连接,将返回-->
              <property name="reapTimeout" value="20"/> <!--最大获取数据时间,如果不设置这个值,Atomikos使用默认的5分钟,那么在处理大批量数据读取的时候,一旦超过5分钟,就会抛出类似 Resultset is close 的错误.-->        
              <property name="maintenanceInterval" value="60" />  <!--连接回收时间-->    
              <property name="loginTimeout" value="60" />     <!--java数据库连接池,最大可等待获取datasouce的时间-->
              <property name="logWriter" value="60"/>
              <property name="minPoolSize" value="1" />  <!-- 连接池中保留的最小连接数   -->
              <property name="maxPoolSize" value="3" />  <!-- 连接池中保留的最大连接数    -->
              <property name="maxIdleTime" value="60" /> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
          </bean> 
           <!-- 配置2个数据源 mysql -->
           <bean id="ds_suicai" parent="abstractXADataSource">  
           	<!-- uniqueResourceName表示唯一资源名,如有多个数据源不可重复; -->
           	<property name="uniqueResourceName" value="suicaifortest" />
           	<!--  xaDataSourceClassName是具体分布式数据源厂商实现; -->
           	<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
           	<!-- xaProperties属性指定具体厂商数据库属性 -->
           	<property name="xaProperties">
                  <props>
                      <prop key="URL">${db.jdbcUrlOne}</prop>
                      <prop key="user">${user}</prop>
                      <prop key="password">${password}</prop>
                  </props>
              </property>
          </bean>  
      	<bean id="ds_kaizhi"  parent="abstractXADataSource">  
      		<!-- uniqueResourceName表示唯一资源名,如有多个数据源不可重复; -->
      		<property name="uniqueResourceName" value="puildingpurchasefortest" />
      		<!-- xaDataSourceClassName是具体分布式数据源厂商实现; -->
      		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
      		<!-- xaProperties属性指定具体厂商数据库属性 -->
      		<property name="xaProperties">
                  <props>
                      <prop key="URL">${db.jdbcUrlTwo}</prop>
                      <prop key="user">${user}</prop>
                      <prop key="password">${password}</prop>
                  </props>
              </property>
          </bean>  
          <!-- 动态配置数据源 --> 
          <bean id="dataSource2" class="com.suicai.common.datasource.DynamicDataSource">  
              <property name="targetDataSources">  
                  <map key-type ="java.lang.String">  
                      <entry value-ref ="ds_suicai" key="ds_suicai"></entry >  
                      <entry value-ref ="ds_kaizhi" key="ds_kaizhi"></entry >  
                  </map > 
              </property>  
              <property name ="defaultTargetDataSource" ref="ds_suicai"></property>  
          </bean>
          <bean id ="sqlSessionFactoryBeanA" class="org.mybatis.spring.SqlSessionFactoryBean" >  
             <!-- 指定数据源 -->  
             <property name ="dataSource" ref="ds_suicai" />  
             <!-- 指定mybatis 的配置文件 -->  
             <property name ="configLocation" value="classpath:mybatis.cfg.xml" />  
      	</bean>
      	<bean id ="sqlSessionFactoryBeanB" class="org.mybatis.spring.SqlSessionFactoryBean" >  
             <!-- 指定数据源 -->  
             <property name ="dataSource" ref="ds_kaizhi" />  
             <!-- 指定mybatis 的配置文件 -->  
             <property name ="configLocation" value="classpath:mybatis.cfg.xml" />  
      	</bean>
      	<!--CustomSqlSessionTemplate继承SqlSessionTemplate重写getSqlSessionFactory方法,具体请下载查看--> 
      	<bean id="sqlSessionTemplate" class="com.suicai.util.CustomSqlSessionTemplate" scope="prototype">
              <constructor-arg ref="sqlSessionFactoryBeanA" />
              <property name="targetSqlSessionFactorys">
                  <map>     
                      <entry value-ref ="sqlSessionFactoryBeanA" key="ds_suicai1"></entry >  
                      <entry value-ref ="sqlSessionFactoryBeanB" key="ds_kaizhi1"></entry >  
                  </map> 
              </property>
          </bean>  
      	<!-- 配置atomikos事务管理器 -->
      	<bean id="atomikosTransactionManager" class = "com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method = "close">    
      	      <property name="forceShutdown" value="true"/>    
      	</bean>    
      	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"></bean>
      	<!-- 配置spring事务管理器 -->
      	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">    
      	    <property name="transactionManager">    
      	        <ref bean="atomikosTransactionManager"/>    
      	    </property>    
      	    <property name="userTransaction">    
      	        <ref bean="atomikosUserTransaction"/>    
      	    </property> 
      	    <!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
      	    <property name="allowCustomIsolationLevels" value="true"/>    
      	</bean>
      	<tx:advice id="advice" transaction-manager="transactionManager">
      		<tx:attributes>
      		    <!-- REQUIRED:必须要有事务, 如果没有就在上下文创建一个 -->
      			<tx:method name="save*" propagation="REQUIRED"/>
      			<tx:method name="creat*" propagation="REQUIRED"/>
      			<tx:method name="add*" propagation="REQUIRED"/>
      			<tx:method name="update*" propagation="REQUIRED"/>
      			<tx:method name="delete*" propagation="REQUIRED"/>
      			<!-- 支持,如果有就有,没有就没有 -->
      			<tx:method name="*" propagation="SUPPORTS"/>
      		</tx:attributes>
      	</tx:advice>
      	<aop:config>
      	    <aop:pointcut expression="execution(* com.suicai.*.service.impl.*.*(..))" id="pointcut"/>
      	    <!-- 吧 tx与aop的配置关联,才是完整的声明事务配置 -->
      	    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
      	</aop:config>
      	<!-- 采用包扫描机制,自动会把指定的包里面的所有dao注册 -->
      	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      		<!-- 注意注入sqlSessionTemplate -->
              <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
      		<property name="basePackage" value="com.suicai.*.dao" />
      	</bean>
      	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      		<property name="viewClass">
      			<value>org.springframework.web.servlet.view.InternalResourceView</value>
      		</property>
      		<!--jsp存放的目录-->
      		<property name="prefix">
      			<value>/</value>
      		</property>
      		<!--jsp文件的后缀-->
      		<property name="suffix">
      			<value>.jsp</value>
      		</property>
      	</bean>
      	<!-- 验证码 -->
      	<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">  
              <property name="config">  
                  <bean class="com.google.code.kaptcha.util.Config">  
                      <constructor-arg>  
                          <props>  
                              <prop key="kaptcha.border">no</prop>  
                              <prop key="kaptcha.border.color">105,179,90</prop>  
                              <prop key="kaptcha.textproducer.font.color">red</prop>  
                              <prop key="kaptcha.image.width">200</prop>  
                              <prop key="kaptcha.textproducer.font.size">60</prop>  
                              <prop key="kaptcha.image.height">80</prop>  
                              <prop key="kaptcha.session.key">code</prop>  
                              <prop key="kaptcha.textproducer.char.length">4</prop>  
                              <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>  
                          </props>  
                      </constructor-arg>  
                  </bean>  
              </property>  
          </bean>
          <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
              <property name="basename" value="classpath:messages"/>  
              <property name="fileEncodings" value="utf-8"/>  
              <property name="cacheSeconds" value="120"/>  
      	</bean>
      </beans>

    以上がSpring トランザクション分離レベル、伝播動作、および spring+mybatis+atomikos により分散トランザクション管理が実現されます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。