Maison  >  Article  >  base de données  >  Niveau d'isolement des transactions Spring, comportement de propagation et spring+mybatis+atomikos réalisent une gestion distribuée des transactions

Niveau d'isolement des transactions Spring, comportement de propagation et spring+mybatis+atomikos réalisent une gestion distribuée des transactions

坏嘻嘻
坏嘻嘻original
2018-09-15 11:04:582389parcourir

Cet article vous apporte du contenu sur le niveau d'isolement des transactions Spring, le comportement de propagation et spring+mybatis+atomikos pour réaliser une gestion distribuée des transactions. Il a une certaine valeur de référence. J'espère qu'il vous sera utile. . Aide.

1. Définition de transaction : Une transaction fait référence à un ensemble de plusieurs unités opérationnelles. Les opérations de plusieurs unités sont indivisibles dans leur ensemble. Soit toutes les opérations échouent, soit toutes réussissent. Il doit suivre quatre principes (ACID).

  1. Atomicité (Atomicité)  : Autrement dit, une transaction est une unité de travail minimale indivisible, et toutes les opérations au sein de la transaction sont soit effectuées, soit aucune. ;

  2. Cohérence  : Les données de la base de données sont dans le bon état avant l'exécution de la transaction, et les données de la base de données doivent toujours être dans le bon état une fois la transaction terminée, c'est-à-dire que les contraintes d'intégrité des données n'ont pas été détruites, comme le virement bancaire, A transfère de l'argent à B, il doit être garanti que l'argent de A doit être transféré à B, et il n'y aura jamais de situation. où l'argent de A est transféré mais B ne le reçoit pas, sinon les données de la base de données auront un statut incohérent (incorrect).

  3. Isolement  : les exécutions de transactions simultanées ne s'affectent pas les unes les autres. Les opérations au sein d'une transaction n'ont aucun impact sur les autres transactions. Cela nécessite que le niveau d'isolement des transactions soit spécifié ; 🎜>

  4. Durabilité (Durabilité)  : Une fois qu'une transaction est exécutée avec succès, ses modifications apportées aux données de la base de données doivent être permanentes et ne le seront pas. Une incohérence ou une perte de données peut survenir en raison de, par exemple, une panne du système ou une panne de courant.

2. Types de transactions

  1. La base de données est divisée en transactions locales et transactions globales

  • Transactions locales : transactions ordinaires, indépendantes d'une base de données, qui peuvent garantir l'ACID pour les opérations sur la base de données.

  • Transactions distribuées : transactions impliquant deux ou plusieurs sources de bases de données, c'est-à-dire des transactions couvrant plusieurs bases de données du même type ou de types hétérogènes (composées de transactions locales de chaque base de données), distribuées. des transactions formelles est de garantir l'ACID de toutes les opérations de ces transactions locales, afin que les transactions puissent s'étendre sur plusieurs bases de données

  • Les types de transactions Java sont divisés en transactions JDBC et transactions JTA ;

    • Transaction JDBC : Il s'agit de la transaction locale dans la transaction de base de données mentionnée ci-dessus, contrôlée et gérée via l'objet

      connexion.

    • Transaction JTA : JTA fait référence à Java Transaction API (Java Transaction API), qui est la spécification de transaction de base de données Java EE

      fournit uniquement une interface de gestion des transactions , qui est contrôlé par l'application. Les fournisseurs de serveurs (tels que WebSphere Application Server) fournissent des implémentations plus puissantes que JDBC et prennent en charge les transactions distribuées .

  • Selon que la programmation est utilisée, elle est divisée en transactions déclaratives et transactions programmatiques. Veuillez vous référer à http://blog.csdn.net/liaohaojian/article/details. /70139151

    • Transactions déclaratives : implémentées via une configuration XML ou des annotations.

    • Transactions programmatiques : implémentez une logique métier via du code de programmation lorsque cela est nécessaire, avec une granularité plus petite.

    3. Niveau d'isolement des transactions Spring : Spring a cinq niveaux d'isolement principaux, qui sont définis dans l'interface TransactionDefinition. En regardant le code source, nous pouvons voir que son isolation_default par défaut (le niveau par défaut de la base de données sous-jacente) et les quatre autres niveaux d'isolation sont cohérents avec le niveau d'isolation de la base de données.

    1. ISOLATION_DEFAULT : Utiliser le niveau d'isolement par défaut de la base de données sous-jacente, quels que soient les paramètres définis par l'administrateur de la base de données

    2. ISOLATION_READ_UNCOMMITTED (lecture non validée)  : Le niveau d'isolement le plus bas, avant que la transaction ne soit validée, elle peut être lue par d'autres transactions (des lectures fantômes, des lectures sales, des lectures non répétables se produiront)

    3. ISOLATION_READ_COMMITTED (lecture validée) : Une transaction ne peut être lue par d'autres transactions qu'après avoir été soumise (ce niveau d'isolement interdit aux autres transactions de lire les données des transactions non validées transactions, donc cela provoquera toujours une lecture fantôme et une lecture non répétable), niveau par défaut du serveur SQL

    4. ISOLATION_REPEATABLE_READ (lecture répétable)  : lecture répétable, garantissant que plusieurs les lectures sont effectuées en même temps Lorsqu'une donnée est générée, sa valeur est cohérente avec le contenu au début de la transaction et il est interdit de lire des données non validées provenant d'autres transactions (cette isolation peut essentiellement empêcher les lectures sales et non -lectures répétables (l'accent est mis sur la modification), mais des lectures fantômes se produiront) (L'accent est mis sur l'ajout et la suppression)) (Niveau par défaut de MySQL, des modifications peuvent être apportées via le niveau de niveau d'isolement des transactions défini )

    5. ISOLATION_SERIALIZABLE (sérialisation)  : Le niveau d'isolement le plus cher et le plus fiable (ce niveau d'isolement peut empêcher les lectures sales, les lectures non répétables et les lectures fantômes)

      1. Mise à jour perdue : Deux transactions mettent à jour une ligne de données en même temps. La mise à jour de la dernière transaction écrasera la mise à jour de la première transaction, entraînant la perte des données mises à jour. par la première transaction. Ceci est dû à l'absence de verrouillage

      2. Lecture fantôme : au cours d'une même opération de transaction, les mêmes données sont lues plusieurs fois (différentes transactions) dans des périodes différentes, et le contenu lu est incohérent (généralement, le nombre de lignes devient plus ou moins).

      3. Lecture sale : Une transaction lit le contenu d'une autre transaction qui n'est pas mentionnée dans la transaction, ce qui est une lecture sale.

      4. Lecture non répétable : Dans une même transaction, le contenu lu plusieurs fois est incohérent (généralement le nombre de lignes reste le même, mais le contenu change).

    La différence entre la lecture fantôme et la lecture non répétable : l'objectif de la lecture fantôme réside dans l'insertion et la suppression, c'est-à-dire que la deuxième requête sera trouver plus d'informations que la première Les données de la requête deviennent moins ou plus, de sorte qu'elles donnent aux gens une illusion. Le point clé de la lecture non répétable est la modification, c'est-à-dire que la deuxième requête trouvera que la requête. les résultats sont incohérents avec les premiers résultats de la requête, c'est-à-dire que le premier résultat n'est plus reproductible.

    Plus le niveau d'isolation de la base de données est élevé, plus le coût d'exécution est élevé et plus la capacité d'exécution simultanée est mauvaise. Par conséquent, des considérations globales doivent être prises en compte lors du développement et de l'utilisation de projets réels afin de prendre en compte les performances de concurrence<.> utilisez généralement pour soumettre le niveau d'isolement de lecture , ce qui peut éviter la perte de mises à jour et les lectures sales. Bien que les lectures non répétables et les lectures fantômes ne puissent pas être évitées, les verrous pessimistes ou optimistes peuvent l'être. utilisé lorsque cela est possible pour résoudre ces problèmes.

    4. Comportement de communication : Il existe sept comportements de communication majeurs, qui sont également définis dans l'interface TransactionDefinition.

    1. PROPAGATION_REQUIRED : Prend en charge la transaction en cours. S'il n'y a pas de transaction en cours, créez-en une nouvelle.

    2. PROPAGATION_SUPPORTS : prend en charge la transaction en cours s'il n'y a pas de transaction actuellement, elle sera exécutée de manière non transactionnelle (il y a une note dans le code source, qui. n'est pas clair, alors laissez-le pour plus tard) sera étudié plus tard).

    3. PROPAGATION_MANDATORY : Prend en charge la transaction en cours, s'il n'y a pas de transaction en cours, une exception sera levée (elle doit être exécutée dans une transaction existante. Les Méthodes métiers ne peuvent pas initier elles-mêmes leurs propres transactions).

    4. PROPAGATION_REQUIRES_NEW : S'il y a actuellement une transaction, la transaction originale sera suspendue.

    5. PROPAGATION_NOT_SUPPORTED : La transaction en cours n'est pas prise en charge et est toujours exécutée de manière non transactionnelle. Si la transaction en cours existe, la transaction est suspendue. .

    6. PROPAGATION_NEVER : La transaction en cours n'est pas prise en charge si la transaction en cours existe, une exception est levée.

    7. PROPAGATION_NESTED : Si la transaction en cours existe, exécuter dans une transaction imbriquée, s'il n'y a pas de transaction en cours, exécuter des opérations similaires à PROPAGATION_REQUIRED (note : Lorsqu'il est appliqué à JDBC, applicable uniquement au pilote JDBC 3.0 ou supérieur).

    5. Prise en charge des transactions Spring

    1. Spring fournit de nombreux gestionnaires de transactions intégrés qui prennent en charge Différentes sources de données. Il existe trois catégories courantes

    • DataSourceTransactionManager : sous le package org.springframework.jdbc.datasource, la gestion des transactions de source de données classe, fournit la gestion des transactions pour une seule source de données javax.sql.DataSource, à condition qu'elle soit utilisée pour la gestion des transactions du framework JDBC et Mybatis.

    • HibernateTransactionManager : sous le package org.springframework.orm.hibernate3, la classe de gestion des transactions de source de données prend en charge une seule transaction org.hibernate.SessionFactory pour l'intégration. . Gestion des transactions dans le framework Hibernate ; Remarque : Ce gestionnaire de transactions ne prend en charge que la version Hibernate3+, et la version Spring3.0+ ne prend en charge que la version Hibernate 3.2+ ; >JtaTransactionManager : situé dans le package org.springframework.transaction.jta, il prend en charge la
      gestion distribuée des transactions

      et délègue la gestion des transactions au serveur d'applications Java EE, ou le personnalise de manière native. Gestionnaire de transactions JTA, imbriqué dans l'application.
    • Les gestionnaires de transactions intégrés héritent tous de la classe abstraite AbstractPlatformTransactionManager, qui à son tour hérite de l'interface PlatformTransactionManagerLe cœur de la prise en charge des transactions par le framework Spring management est le gestionnaire de transactions Résumé : Pour différents frameworks d'accès aux données, l'interface de stratégie PlatformTransactionManager est implémentée pour prendre en charge la gestion des transactions de plusieurs frameworks d'accès aux données.

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

      2. La configuration des transactions distribuées Spring

      • fait référence à la source de données JNDI du serveur d'applications (telle que comme Tomcat) et l'implémente indirectement. La gestion des transactions JTA s'appuie sur le serveur d'application

      • pour intégrer directement JOTM (site officiel : http://jotm.objectweb.org/) et Atomikos (site officiel site Web : https://www.atomikos.com/) fournit la gestion des transactions JTA (pas de prise en charge du serveur d'applications, souvent utilisé pour les tests unitaires)

      • Utilisez des gestionnaires de transactions spécifiques au serveur d'applications pour utiliser fonctionnalités avancées des transactions JTA (Weblogic, Websphere )

      1). Référencez la source de données JNDI du serveur d'application (comme Tomcat) pour implémenter indirectement la gestion des transactions JTA. suit

      <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) Utilisez Atomikos pour implémenter la gestion distribuée des transactions, la configuration est la suivante :

      <?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>

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn