Spring學習8-Spring事務管理(編程式事務管理)


一、Spring事務的相關知識
  1、事務是指一系列獨立的操作,但在概念上具有原子性。 比如轉賬:A賬號-100, B賬號+100,完成。這兩個操作獨立是沒問題的。 但在邏輯上,要么全部完成,要么一起失敗。
   1)jdbc事務:每個Connection都帶有一個事務,只是默認被設置為自動提交。一個連接可以有多個事務。對於JDBC,只有在同一個連接內,才有討論是否提交的前提。
   2)Hibernate事務:本質上也是使用JDBC來處理事務。但是不是直接操作,而是使用Session來操作事務。Session.getTranction();
  ####事務應該要在service層(也可以叫事務層)進行控制。
為什么用Spring來進行事務控制?
   如果要手動進行控制事務的話,對於JDBC,service層需要Connection;對於Hibernate,serivice層需要 Session。若一個項目要實現JDBC和Hibernate或其他的互換,我們要做Service層修改很多東西;而且對於Service層來說,他 應該關心的不應該是這些,而是業務邏輯。因此,首先手動控制不能實現組件的替換,其次這些API也不應該出現在service層,但是Spring的 IOC很好的解決了這樣的問題。

  2、JavaEE傳統事務有兩種策略:全局事務和局部事務全局事務由應用服務器管理,需要底層服務器JTA支持(如WebLogic、JBoss等)。局部事務和底層采用的持久化技術有關:當采用JDBC持久化技術時,需要使用Connetion對象來操作事務;而采用Hibernate持久化技術時,需要使用Session對象來操作事務。
   全局事務可以跨多個事務性的資源(典型例子是關系數據庫和消息隊列);使用局部事務,應用服務器不需要參與事務管理,因此不能保證跨多個事務性資源的事務的正確性。當然,實際上大部分應用都使用單一事務性的資源。
   Spring事務策略是通過PlatformTransactionManager接口體現的,該接口是Spring事務策略的核心,是一個與任何事務策略分離的接口,隨着底層不同事務策略的切換,應用必須采用不同的實現類。結合Spring的IoC容器,可以向該接口注入相關的平台特性。
  3、Spring的事務管理,主要有兩種方式實現,一種是在代碼中編寫(編程式事務管理),一種是聲明式事務(又可分為AOP式事務管理和注解式事務管理)。在代碼中編寫要更加細粒度,而很多時候我們只需要簡單的事務處理,那就可以用聲明式事務。

Spring的事務管理器

事務管理器實現

目標

org.springframework.jdbc.datasource.DataSourceTransactionManager

在JDBC DataSource中管理事務

(須注入數據源datasource  Bean參數)

org.springframework.orm.hibernate.HibernateTransactionManager

管理Hibernate事務

(須注入SessionFactory Bean參數)

org.springframework.orm.jdo.JdoTransactionManager

管理JDO事務

org.springframework.transaction.jta.JtaTransactionManager

使用一個JTA管理事務,在一個事務跨越多個資源時必須使用

(無須注入參數)

org.springframework.orm.ojb.PersistenceBrokerTransactionManager

管理Apache的OJB事務

 這些事務管理器的的父接口都是PlatformTransactionManager.Spring的事務管理機制是一種典型的策略模式PlatformTransactionManager 代表事務管理接口(該接口定義了下面所說的三個方法),他並不知道底層如何管理事務,他只要求事務管理的實現類提供開始事務 (getTransaction())、提交事務(commit())、回滾事務(rollback()),但具體如何實現則交給具體的實現類完成——不 同的實現類代表不同的事務管理策略。

  說明:

  1、JTA事務管理器無須注入參數,是因為全局事務的JTA資源由JAVA EE服務器提供,而Spring容器能自行從JAVA EE服務器中獲取該事務資源,所以無須使用依賴注入來配置。

  2、當使用JTA全局事務策略時,實際底層須應用服務器支持,而不同的應用服務器所提供的JTA全局事務可能存在細節上的差異,因此實際配置全局事務管理器是可能需要使用JtaTransactionManager的子類,如:OC4JtaTransactionManager(Oracle提供的應用服務器)、WebLogicJtaTransactionManager(Bea提供的WebLogic)、UowJtaTransactionManager(IBM提供的WebSphere)等

二、Spring編程式事務示例

步驟一、編寫spring配置文件

下面實例使用DataSourceTransactionManager來管理JDBC事務。
查看Spring的配置信息:(applicationContext.xml):

<?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"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
     <bean id="propertyConfig"
         class="org.springframework.beans.factory.config.

  PropertyPlaceholderConfigurer">
         <property name="location">
             <value>connect.properties</value>
         </property>
     </bean>
 
     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
         <property name="driverClassName">
             <value>${db.driver}</value>
         </property>
         <property name="url">
             <value>${db.url}</value>
         </property>
         <property name="username">
             <value>${db.username}</value>
         </property>
         <property name="password">
             <value>${db.password}</value>
         </property>
     </bean>
 
     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
         <property name="dataSource">
             <ref bean="dataSource" />
         </property>
     </bean>
 
     <!-- JDBC事務管理器 注意:事務管理器傳的參數是數據源-->
     <bean id="transactionManager"
         class="org.springframework.jdbc.datasource.

       DataSourceTransactionManager" scope="singleton">
         <property name="dataSource">
             <ref bean="dataSource" />
         </property>
     </bean>

 
     <!-- 聲明事務模板 -->
     <bean id="transactionTemplate"
         class="org.springframework.transaction.support.

   TransactionTemplate">
         <property name="transactionManager">
             <ref bean="transactionManager" />
         </property>
     </bean>

 
     <bean id="bankDao" class="com.sunflower.dao.BankDaoImp">
         <property name="jdbcTemplate">
             <ref bean="jdbcTemplate" />
         </property>
         <property name="transactionTemplate">
             <ref bean="transactionTemplate" />
         </property>
     </bean>
 </beans>

上 面代碼中配置了一個org.springframework.transaction.support.TransactionTemplate實例,要 在代碼中添加事務,Spring為我們提供了一種方法就是使用TransactionTemplate類。我們要為 TransactionTemplate裝配一個TransactionManager,

如果是要配置Hibernate事務,要進行如下配置:(配置一個sessionFactory):
<!-- Hibernate事務管理器  注意:此事務管理器參數是
sessionFactory-->
     <bean id="transactionManager"
  
class="org.springframework.orm.hibernate3.
   HibernateTransactionManager"
scope="singleton">    
         <property name="sessionFactory">
             <ref bean="sessionFactory" />
         </property>

     </bean>

 如果是要配置JTA事務,要進行如下配置(無須參數):
 <bean id="
transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" scope="singleton" >
  </bean>



 步驟二、使用TransactionTemplate進行事務管理:

package com.sunflower.dao;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
 
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowCallbackHandler;
 import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.TransactionCallback;
 import org.springframework.transaction.support.TransactionTemplate;
 
 import com.sunflower.entity.People;
 
 
 public class BankDaoImp implements BankDao {
     private JdbcTemplate jdbcTemplate;
     private TransactionTemplate transactionTemplate;
 
     public JdbcTemplate getJdbcTemplate() {
         return jdbcTemplate;
     }
 
     public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
         this.jdbcTemplate = jdbcTemplate;
     }
 
     public TransactionTemplate getTransactionTemplate() {
         return transactionTemplate;
     }
 
     public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
         this.transactionTemplate = transactionTemplate;
     }
 
     @Override
     public double getMoney(final People people) {
         double money = people.getMoney();
         // 開始事務,如果出現狀況則回滾
        transactionTemplate.execute(new TransactionCallback<People>() {
             @Override
             public People doInTransaction(TransactionStatus ts) {
                 try {
                     final People people2 = new People();
                     // 使用JdbcTemplate進行持久化層操作
                     String sql = "select money from bank where name = ?";
                     Object[] params = new Object[] { people.getName() };
                     // 查詢
                     jdbcTemplate.query(sql, params, new RowCallbackHandler() {
                         @Override
                         public void processRow(ResultSet rs)
                                 throws SQLException {
                             people2.setMoney(rs.getDouble("money"));
                             System.out.println(people.getName() + "用戶還有"
                                     + rs.getDouble("money") + "元余款");
                             System.out.println(people.getName() + "要從賬戶中取出"
                                     + people.getMoney() + "元");
                             if (people2.getMoney() < people.getMoney()) {
                                 System.out.println("余額不足");
                                 people.setMoney(-1);
                                 return;
                             }
                         }
                     });
 
                     if (people.getMoney() < 0)
                         return null;
                     else {
                         sql = "update bank set money = ? where name = ?";
                         Object[] params2 = new Object[] {
                                 people2.getMoney() - people.getMoney(),
                                 people.getName() };
                         jdbcTemplate.update(sql, params2);
                         System.out.println("剩余余額:"
                                 + (people2.getMoney() - people.getMoney()));
                     }
                 }
                 catch (Exception e) {
                     ts.setRollbackOnly();
                 }
 
                 // 如果成功,事務被提交
                 return people;
             }
         });

 
         return people.getMoney();
     }
 }
調 用TransactionTemplate實例的execute()方法將執行包含在TransactionCallback實例里的代碼。如果代碼出現 異常,調用TransactionStatus對象的setRollbackOnly()將事務回滾。否則,如果doInTransaction()方法 正常返回,事務將被提交。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM