spring事务管理总结



项目中一直用spring,事务管理这块还是遇到了挺多问题。下面把这些问题总结一下,以供大家参考和讨论。下面先提出这些问题

问题一:spring中的声明式事务很方便,但有时候还是不能很好的满足需求。比如:项目中一些业务数据要从Excel中导入,一次导入可能上千条,每一条数据又涉及多个表(这几个表的数据需要在一个事务中)。这种情况可能声明式事务就不好办了。
问题二:“PROPAGATION_REQUIRED,readOnly”,只读事务和“PROPAGATION_REQUIRED”区别在哪里?
问题三:事务放在service层中,service中这个类的方法之间的调用,事务是什么样的?service层调用另外一个service层的类的方法,事务又是怎样的?
问题四:编程式事务中,多次提交报错:Transaction is already completed do not call commit or rollback more than once per transaction,如何解决?
首先来看一%EsactionManager;  

  • }  
  • //循环提交示例  
  • public void drExcel()  
  • {  
  •     TransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);  
  •     TransactionStatus status=null;  
  •     for(int i = 0;i<10;i++)  
  •     {  
  •         try  
  •         {  
  •                //重置事务状态。没这句话会报错。这就是问题四的解决方法  
  •                status=platformTransactionManager.getTransaction(definition);  
  •             //以下代码是操作数据  
  •             //......  
  •             //提交  
  •             platformTransactionManager.commit(status);  
  •         }catch(Exception e)  
  •         {  
  •             e.printStackTrace();  
  •             platformTransactionManager.rollback(status);  
  •         }  
  •   
  •     }  
  • }  
      	//采用注入的方式得到PlatformTransactionManager
      	private PlatformTransactionManager platformTransactionManager=null;
      
      	public PlatformTransactionManager getPlatformTransactionManager()
      	{
      		return platformTransactionManager;
      	}
      
      	public void setPlatformTransactionManager(
      			PlatformTransactionManager platformTransactionManager)
      	{
      		this.platformTransactionManager = platformTransactionManager;
      	}
      	//循环提交示例
      	public void drExcel()
      	{
      		TransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
      		TransactionStatus status=null;
      		for(int i = 0;i<10;i++)
      		{
      			try
      			{
                      //重置事务状态。没这句话会报错。这就是问题四的解决方法
                      status=platformTransactionManager.getTransaction(definition);
      				//以下代码是操作数据
      				//......
      				//提交
      				platformTransactionManager.commit(status);
      			}catch(Exception e)
      			{
      				e.printStackTrace();
      				platformTransactionManager.rollback(status);
      			}
      
      		}
      	}


      下面贴出transactionTemplate使用片断,以供以后用到时参考:

      1. public void createPerson(final Person person) {  
      2.    transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
      3.    transactionTemplate.execute(new TransactionCallbackWithoutResult(){    // 使用无返回值的事务回调接口  
      4.     @Override  
      5.     protected void doInTransactionWithoutResult(TransactionStatus arg0) {  
      6.      getHibernateTemplate().save(person);      
      7.     }     
      8.    });  
      9. }  
      10.   
      11. public Person queryOnePerson(final String hql) {  
      12.    transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
      13.    return (Person)transactionTemplate.execute(new TransactionCallback(){     // 使用带返回值的事务回调接口  
      14.   
      15.     public Object doInTransaction(TransactionStatus arg0) {  
      16.      return getHibernateTemplate().find(hql).get(0);  
      17.     }     
      18.    });  
      19. }  
      public void createPerson(final Person person) {
         transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
         transactionTemplate.execute(new TransactionCallbackWithoutResult(){    // 使用无返回值的事务回调接口
          @Override
          protected void doInTransactionWithoutResult(TransactionStatus arg0) {
           getHibernateTemplate().save(person);    
          }   
         });
      }
      
      public Person queryOnePerson(final String hql) {
         transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
         return (Person)transactionTemplate.execute(new TransactionCallback(){     // 使用带返回值的事务回调接口
      
          public Object doInTransaction(TransactionStatus arg0) {
           return getHibernateTemplate().find(hql).get(0);
          }   
         });
      }
      
      以上问题一和问题四基本上解决。
      再看问题二,我在oracle数据库试验了下,“PROPAGATION_REQUIRED,readOnly”下进行事务操作是可以的,和“PROPAGATION_REQUIRED”没有区别,可能是要告诉数据库我只进行只读操作,数据库可以进行对sql进行一些优化吧?如果进行insert update delete操作也还是放在一个事务中进行的。我认为对于不需要事务的操作,应该配置成“PROPAGATION_SUPPORTS”还是更合理一些。有待大家讨论。
      问题三,service中这个类的方法之间的调用,你比如我现在事务配置成如下所示:
      1. <bean id="baseTransactionProxy"  
      2.     class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"  
      3.     abstract="true">  
      4.     <property name="transactionManager">  
      5.         <ref bean="transactionManager" />  
      6.     </property>  
      7.     <property name="transactionAttributes">  
      8.         <props>  
      9.             <prop key="insert*">PROPAGATION_REQUIRED</prop>  
      10.             <prop key="update*">PROPAGATION_REQUIRED</prop>  
      11.             <prop key="delete*">PROPAGATION_REQUIRED</prop>  
      12.             <prop key="*">PROPAGATION_SUPPORTS</prop>  
      13.         </props>  
      14.     </property>  
      15. </bean>  
      	<bean id="baseTransactionProxy"
      		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
      		abstract="true">
      		<property name="transactionManager">
      			<ref bean="transactionManager" />
      		</property>
      		<property name="transactionAttributes">
      			<props>
      				<prop key="insert*">PROPAGATION_REQUIRED</prop>
      				<prop key="update*">PROPAGATION_REQUIRED</prop>
      				<prop key="delete*">PROPAGATION_REQUIRED</prop>
      				<prop key="*">PROPAGATION_SUPPORTS</prop>
      			</props>
      		</property>
      	</bean>

      某service1类中有方法两个方法importData(有一个对数据库操A)、insertData(有一个对数据库的操作B)方法。
      试验一importData方法中调用了insertData的方法
      试验结果:action中调用service1中的importData方法,这时候是没有事务的。
      试验二insertData调用了insertData方法
      试验结果:action中调用service1中的insertData方法是有事务的。
      这就说明service方法中事务是根据该service层中最开始方法的事务属性来的。
      那么service类之间方法调用会是什么样的?我想也应该是这样的。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值