国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > Java > 正文

Spring中事務管理的四種方法(銀行轉賬為例)

2024-07-14 08:40:49
字體:
來源:轉載
供稿:網友

前言

本文配套示例代碼下載地址(完整可運行,含sql文件,下載后請修改數據庫配置):點擊這里下載

一、事務的作用

  將若干的數據庫操作作為一個整體控制,一起成功或一起失敗。

  原子性:指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。

  一致性:指事務前后數據的完整性必須保持一致。

  隔離性:指多個用戶并發訪問數據庫時,一個用戶的事務不能被其他用戶的事務所干擾,多個并發事務之間數據要相互隔離。

  持久性:指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,即時數據庫發生故障也不應該對其有任何影響。

二、Spring事務管理高層抽象主要包括3個接口

  --Platform TransactionManager 事務管理器(提交、回滾事務)

     Spring為不同的持久化框架提供了不同的Platform TransactionManager接口實現。如:

        使用Spring JDBC或iBatis進行持久化數據時使用DataSourceTransactionManager

        使用Hibernate3.0版本進行持久化數據時使用HibernateTransactionManager

  --TransactionDefinition 事務定義信息(隔離、傳播、超時、只讀)

        臟讀:一個事務讀取了另一個事務改寫但還未提交的數據,如果這些數據被回滾,則讀到的數據是無效的。

        不可重復讀:在同一事務中,多次讀取同一數據返回的結果有所不同。

        幻讀:一個事務讀取了幾行記錄后,另一個事務插入一些記錄,幻讀就發生了。再后來的查詢中,第一個事務就會發現有些原來沒有的記錄。

        事務隔離級別:(五種)

  •     DEFAULT--使用后端數據庫默認的隔離級別(Spring中的選擇項)
  •     READ_UNCOMMITED--允許你讀取還未提交的改變了的數據。可能導致臟、幻、不可重復讀
  •     READ_COMMITTED--允許在并發事務已經提交后讀取。可防止臟讀,但幻讀和不可重復讀仍可發生
  •     REPEATABLE_READ--對相同字段的多次讀取是一致的,除非數據被事務本身改變。可防止臟、不可重復讀,但幻讀仍可能發生
  •     SERIALIZABLE--完全服從ACID的隔離級別,確保不發生臟、幻、不可重復讀。這在所有的隔離級別中是最慢的,它是典型的通過完全鎖定在事務中涉及的數據表來完成的

    其中,MySQL默認采用REPEATABLE_READ隔離級別;Oracle默認采用READ_COMMITTED隔離級別

        事務傳播行為:(七種)

  •     REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
  •     SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。
  •     MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
  •     REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
  •     NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  •     NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。
  •     NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與REQUIRED類似的操作。擁有多個可以回滾的保存點,內部回滾不會對外部事務產生影響。只對DataSourceTransactionManager有效

  --TransactionStatus 事務具體運行狀態

三、Spring提供了以下方法控制事務

  a.編程式事務管理(基于Java編程控制,很少使用)--見demo1包

       利用TransactionTemplate將多個DAO操作封裝起來

  *b.聲明式事務管理(基于Spring的AOP配置控制)

       -基于TransactionProxyFactoryBean的方式.(很少使用)--見demo2包

            需要為每個進行事務管理的類,配置一個TransactionProxyFactoryBean進行增強.

       -基于XML配置(經常使用)--見demo3包

            一旦配置好之后,類上不需要添加任何東西。

            如果Action作為目標對象切入事務,需要在<aop:config>元素里添加proxy-target-class="true"屬性。原因是通知Spring框架采用CGLIB技術生成具有事務管理功能的Action類。

       -基于注解(配置簡單,經常使用)--見demo4包

            在applicationContext.xml中開啟事務注解配置。(applicationContext.xml中只需定義Bean并追加以下元素)

<bean id="txManager" class="..."> <property name="sessionFactory"> </property><tx:annotation-driven transaction-manager="txManager"/>

            在目標組件類中使用@Transactional,該標記可定義在類前或方法前。

四、示例(銀行轉賬)

        --編程式

/**  * @Description:轉賬案例的DAO層接口  *  */ public interface AccountDao {  /**  * @param out  * :轉出賬號  * @param money  * :轉賬金額  */  public void outMoney(String out, Double money);   /**  *  * @param in  * :轉入賬號  * @param money  * :轉賬金額  */  public void inMoney(String in, Double money); } 
/**  * @Description:轉賬案例的DAO層實現類  */ public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {  /**  * @param out  * :轉出賬號  * @param money  * :轉賬金額  */  @Override  public void outMoney(String out, Double money) {  String sql = "update account set money = money-? where name = ?";  this.getJdbcTemplate().update(sql, money, out);  }  /**  * @param in  * :轉入賬號  * @param money  * :轉賬金額  */  @Override  public void inMoney(String in, Double money) {  String sql = "update account set money = money+? where name = ?";  this.getJdbcTemplate().update(sql, money, in);  } } 
/**  * @Description:轉賬案例的業務接口  *  */ public interface AccountService {  /**  * @param out :轉出賬號  * @param in :轉入賬號  * @param money :轉賬金額  */  public void transfer(String out,String in,Double money); } 
/**  * @Description:轉賬案例的業務層實現類  */ public class AccountServiceImpl implements AccountService {  // 注入轉賬的DAO  private AccountDao accountDao;   // 注入事務管理的模板  private TransactionTemplate transactionTemplate;   /**  * @param out  * :轉出賬號  * @param in  * :轉入賬號  * @param money  * :轉賬金額  */  @Override  public void transfer(final String out, final String in, final Double money) {   // 未經事務控制的業務處理操作,如果過程中出異常,則導致前面的操作能完成,后面的不能,即轉賬成功但未收到轉賬款  // accountDao.outMoney(out, money);  // int i = 1/0;  // accountDao.inMoney(in, money);   transactionTemplate.execute(new TransactionCallbackWithoutResult() {   @Override  protected void doInTransactionWithoutResult(   TransactionStatus transactionStatus) {  accountDao.outMoney(out, money);  // int i = 1 / 0;//事務控制,即出現異常,該段內代碼都執行失效  accountDao.inMoney(in, money);  }  });  }   public void setAccountDao(AccountDao accountDao) {  this.accountDao = accountDao;  }   public void setTransactionTemplate(TransactionTemplate transactionTemplate) {  this.transactionTemplate = transactionTemplate;  } } 

applicationContext1.xml

<!-- 引入外部的屬性文件 -->  <context:property-placeholder location="classpath:jdbc.properties"/>   <!-- 配置c3p0連接池 -->  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  </bean>   <!-- 配置業務層類 -->  <bean id="accountService" class="com.zs.spring.demo1.AccountServiceImpl">  <property name="accountDao" ref="accountDao" />  <!-- 注入事務管理的模板 -->  <property name="transactionTemplate" ref="transactionTemplate" />  </bean>   <!-- 配置DAO類(簡化,會自動配置JdbcTemplate) -->  <bean id="accountDao" class="com.zs.spring.demo1.AccountDaoImpl">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- 配置DAO類(未簡化) -->  <!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  <property name="dataSource" ref="dataSource" />  </bean>  <bean id="accountDao" class="com.zs.spring.demo1.AccountDaoImpl">  <property name="jdbcTemplate" ref="jdbcTemplate" />  </bean> -->   <!-- ==================================1.編程式的事務管理=============================================== -->  <!-- 配置事務管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- 配置事務管理的模板:Spring為了簡化事務管理的代碼而提供的類 -->  <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  <property name="transactionManager" ref="transactionManager"/>  </bean> 

測試:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext1.xml") public class TransactionTest {  @Resource(name = "accountService")  private AccountService accountService;   @Test  public void demo1() {  accountService.transfer("aaa", "bbb", 200d);  } } 

    --基于TransactionProxyFactoryBean的方式

public class AccountServiceImpl implements AccountService {  // 注入轉賬的DAO  private AccountDao accountDao;   /**  * @param out  *  :轉出賬號  * @param in  *  :轉入賬號  * @param money  *  :轉賬金額  */  @Override  public void transfer(String out, String in, Double money) {  accountDao.outMoney(out, money);  // int i = 1/0;  accountDao.inMoney(in, money);  }   public void setAccountDao(AccountDao accountDao) {  this.accountDao = accountDao;  } } 

applicationContext2.xml

<!-- 引入外部的屬性文件 -->  <context:property-placeholder location="classpath:jdbc.properties"/>   <!-- 配置c3p0連接池 -->  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  </bean>   <!-- 配置業務層類 -->  <bean id="accountService" class="com.zs.spring.demo2.AccountServiceImpl">  <property name="accountDao" ref="accountDao" />  </bean>   <!-- 配置DAO類(簡化,會自動配置JdbcTemplate) -->  <bean id="accountDao" class="com.zs.spring.demo2.AccountDaoImpl">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- ==================================2.使用XML配置聲明式的事務管理(原始方式)=============================================== -->   <!-- 配置事務管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- 配置業務層的代理 -->  <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  <!-- 配置目標對象 -->  <property name="target" ref="accountService" />  <!-- 注入事務管理器 -->  <property name="transactionManager" ref="transactionManager"></property>  <!-- 注入事務的屬性 -->  <property name="transactionAttributes">   <props>   <!--    prop的格式:    * PROPAGATION :事務的傳播行為    * ISOTATION :事務的隔離級別    * readOnly :只讀    * -EXCEPTION :發生哪些異常回滾事務    * +EXCEPTION :發生哪些異常不回滾事務    -->   <prop key="transfer">PROPAGATION_REQUIRED</prop>   <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->   <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->   </props>  </property>  </bean> 

測試:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class TransactionTest {  /**  * 一定要注入代理類:因為代理類進行增強的操作  */  // @Resource(name="accountService")  @Resource(name = "accountServiceProxy")  private AccountService accountService;   @Test  public void demo1() {  accountService.transfer("aaa", "bbb", 200d);  } } 

    --基于XML配置

public class AccountServiceImpl implements AccountService {  // 注入轉賬的DAO  private AccountDao accountDao;   /**  * @param out  *  :轉出賬號  * @param in  *  :轉入賬號  * @param money  *  :轉賬金額  */  @Override  public void transfer(String out, String in, Double money) {  accountDao.outMoney(out, money);  // int i = 1/0;  accountDao.inMoney(in, money);   }   public void setAccountDao(AccountDao accountDao) {  this.accountDao = accountDao;  } } 

applicationContext3.xml

<!-- 引入外部的屬性文件 -->  <context:property-placeholder location="classpath:jdbc.properties"/>   <!-- 配置c3p0連接池 -->  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  </bean>   <!-- 配置業務層類 -->  <bean id="accountService" class="com.zs.spring.demo3.AccountServiceImpl">  <property name="accountDao" ref="accountDao" />  </bean>   <!-- 配置DAO類(簡化,會自動配置JdbcTemplate) -->  <bean id="accountDao" class="com.zs.spring.demo3.AccountDaoImpl">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- ==================================3.使用XML配置聲明式的事務管理,基于tx/aop=============================================== -->   <!-- 配置事務管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- 配置事務的通知 -->  <tx:advice id="txAdvice" transaction-manager="transactionManager">  <tx:attributes>   <!--   propagation :事務傳播行為   isolation :事務的隔離級別   read-only :只讀   rollback-for:發生哪些異常回滾   no-rollback-for :發生哪些異常不回滾   timeout :過期信息   -->   <tx:method name="transfer" propagation="REQUIRED"/>  </tx:attributes>  </tx:advice>   <!-- 配置切面 -->  <aop:config>  <!-- 配置切入點 -->  <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>  <!-- 配置切面 -->  <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>  </aop:config> 

測試:

/**  * @Description:Spring的聲明式事務管理的方式二:基于AspectJ的XML方式的配置  */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext3.xml") public class TransactionTest {  /**  * 一定要注入代理類:因為代理類進行增強的操作  */  @Resource(name = "accountService")  private AccountService accountService;   @Test  public void demo1() {  accountService.transfer("aaa", "bbb", 200d);  } } 

    --基于注解

/**  * @Transactional中的的屬性 propagation :事務的傳播行為 isolation :事務的隔離級別 readOnly :只讀  *   rollbackFor :發生哪些異常回滾 noRollbackFor :發生哪些異常不回滾  *   rollbackForClassName 根據異常類名回滾  */ @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false) public class AccountServiceImpl implements AccountService {  // 注入轉賬的DAO  private AccountDao accountDao;   /**  * @param out  *  :轉出賬號  * @param in  *  :轉入賬號  * @param money  *  :轉賬金額  */  @Override  public void transfer(String out, String in, Double money) {  accountDao.outMoney(out, money);  // int i = 1/0;  accountDao.inMoney(in, money);  }   public void setAccountDao(AccountDao accountDao) {  this.accountDao = accountDao;  } } 

applicationContext4.xml

<!-- 引入外部的屬性文件 -->  <context:property-placeholder location="classpath:jdbc.properties"/>   <!-- 配置c3p0連接池 -->  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  </bean>   <!-- 配置業務層類 -->  <bean id="accountService" class="com.zs.spring.demo4.AccountServiceImpl">  <property name="accountDao" ref="accountDao" />  </bean>   <!-- 配置DAO類(簡化,會自動配置JdbcTemplate) -->  <bean id="accountDao" class="com.zs.spring.demo4.AccountDaoImpl">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- ==================================4.使用注解配置聲明式事務============================================ -->   <!-- 配置事務管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource" />  </bean>   <!-- 開啟注解事務 -->  <tx:annotation-driven transaction-manager="transactionManager"/> 

測試:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext4.xml") public class TransactionTest {  /**  * 一定要注入代理類:因為代理類進行增強的操作  */  @Resource(name = "accountService")  private AccountService accountService;   @Test  public void demo1() {  accountService.transfer("aaa", "bbb", 200d);  } } 

具體代碼和數據庫文件參考項目完整代碼:

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 井研县| 宜阳县| 襄汾县| 阳曲县| 安塞县| 疏附县| 浮山县| 原平市| 德惠市| 湘乡市| 长寿区| 和政县| 博白县| 宣汉县| 斗六市| 迁安市| 崇礼县| 江孜县| 开鲁县| 巩留县| 奉新县| 怀宁县| 昌图县| 若尔盖县| 玛曲县| 额济纳旗| 洪雅县| 托克托县| 无为县| 莱西市| 萨嘎县| 碌曲县| 绥德县| 莎车县| 湖南省| 漯河市| 西宁市| 长阳| 彰化县| 崇信县| 南汇区|