欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring中的事務(wù)管理實(shí)例詳解

 更新時(shí)間:2014年11月19日 10:52:46   投稿:shichen2014  
這篇文章主要介紹了Spring中的事務(wù)管理,以實(shí)例形式詳細(xì)分析了事務(wù)的概念與特性以及事物管理的具體用法,需要的朋友可以參考下

本文實(shí)例講述了Spring中的事務(wù)管理。分享給大家供大家參考。具體分析如下:

事務(wù)簡(jiǎn)介:

事務(wù)管理是企業(yè)級(jí)應(yīng)用程序開(kāi)發(fā)中必不可少的技術(shù),用來(lái)確保數(shù)據(jù)的完整性和一致性

事務(wù)就是一系列的動(dòng)作,它們被當(dāng)作一個(gè)單獨(dú)的工作單元。這些動(dòng)作要么全部完成,要么全部不起作用

事務(wù)的四個(gè)關(guān)鍵屬性(ACID)

① 原子性(atomicity):事務(wù)室一個(gè)原子操作,有一系列動(dòng)作組成。事務(wù)的原子性確保動(dòng)作要么全部完成,要么完全不起作用
② 一致性(consistency):一旦所有事務(wù)動(dòng)作完成,事務(wù)就被提交。數(shù)據(jù)和資源就處于一種滿足業(yè)務(wù)規(guī)則的一致性狀態(tài)中
③ 隔離性(isolation):可能有許多事務(wù)會(huì)同時(shí)處理相同的數(shù)據(jù),因此每個(gè)事物都應(yīng)該與其他事務(wù)隔離開(kāi)來(lái),防止數(shù)據(jù)損壞
④ 持久性(durability):一旦事務(wù)完成,無(wú)論發(fā)生什么系統(tǒng)錯(cuò)誤,它的結(jié)果都不應(yīng)該受到影響。通常情況下,事務(wù)的結(jié)果被寫(xiě)到持久化存儲(chǔ)器中

Spring中的事務(wù)管理

作為企業(yè)級(jí)應(yīng)用程序框架,Spring在不同的事務(wù)管理API之上定義了一個(gè)抽象層。而應(yīng)用程序開(kāi)發(fā)人員不必了解底層的事務(wù)管理API,就可以使用Spring的事務(wù)管理機(jī)制。

Spring既支持編程式事務(wù)管理,也支持聲明式的事務(wù)管理

編程式事務(wù)管理:將事務(wù)管理代碼嵌入到業(yè)務(wù)方法中來(lái)控制事務(wù)的提交和回滾,在編程式事務(wù)中,必須在每個(gè)業(yè)務(wù)操作中包含額外的事務(wù)管理代碼

聲明式事務(wù)管理:大多數(shù)情況下比編程式事務(wù)管理更好用。它將事務(wù)管理代碼從業(yè)務(wù)方法中分離出來(lái),以聲明的方式來(lái)實(shí)現(xiàn)事務(wù)管理。事務(wù)管理作為一種橫切關(guān)注點(diǎn),可以通過(guò)AOP方法模塊化。Spring通過(guò)Spring AOP框架支持聲明式事務(wù)管理。

Spring事務(wù)的傳播屬性:

當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),必須指定事務(wù)應(yīng)該如何傳播。例如:方法可能繼續(xù)在現(xiàn)有事務(wù)中運(yùn)行,也可能開(kāi)啟一個(gè)新事務(wù),并在自己的事務(wù)中運(yùn)行。

事務(wù)的傳播行為可以由傳播屬性指定。Spring定義了7種傳播行為:

Spring支持的事務(wù)傳播行為
傳播行為 含義
PROPAGATION_MANDATORY 表示該方法必須在事務(wù)中運(yùn)行,如果當(dāng)前事務(wù)不存在,則會(huì)拋出一個(gè)異常
PROPAGATION_NESTED 表示如果當(dāng)前已經(jīng)存在一個(gè)事務(wù),那么該方法將會(huì)在嵌套事務(wù)中運(yùn)行。嵌套的事務(wù)可以獨(dú)立于當(dāng)前事務(wù)進(jìn)行單獨(dú)地提交或回滾。如果當(dāng)前事務(wù)不存在,那么其行為與PROPAGATION_REQUIRED一樣。注意各廠商對(duì)這種傳播行為的支持是有所差異的??梢詤⒖假Y源管理器的文檔來(lái)確認(rèn)它們是否支持嵌套事務(wù)
PROPAGATION_NEVER   表示當(dāng)前方法不應(yīng)該運(yùn)行在事務(wù)上下文中。如果當(dāng)前正有一個(gè)事務(wù)在運(yùn)行,則會(huì)拋出異常
PROPAGATION_NOT_SUPPORTED 表示該方法不應(yīng)該運(yùn)行在事務(wù)中。如果存在當(dāng)前事務(wù),在該方法運(yùn)行期間,當(dāng)前事務(wù)將被掛起。如果使用JTATransactionManager的話,則需要訪問(wèn)TransactionManager
PROPAGATION_REQUIRED 表示當(dāng)前方法必須運(yùn)行在事務(wù)中。如果當(dāng)前事務(wù)存在,方法將會(huì)在該事務(wù)中運(yùn)行。否則,會(huì)啟動(dòng)一個(gè)新的事務(wù)
PROPAGATION_REQUIRED_NEW 表示當(dāng)前方法必須運(yùn)行在它自己的事務(wù)中。一個(gè)新的事務(wù)將被啟動(dòng)。如果存在當(dāng)前事務(wù),在該方法執(zhí)行期間,當(dāng)前事務(wù)會(huì)被掛起。如果使用JTATransactionManager的話,則需要訪問(wèn)TransactionManager
PROPAGATION_SUPPORTS 表示當(dāng)前方法不需要事務(wù)上下文,但是如果存在當(dāng)前事務(wù)的話,那么該方法會(huì)在這個(gè)事務(wù)中運(yùn)行

其中PROPAGATION_REQUIRED為默認(rèn)的傳播屬性

并發(fā)事務(wù)所導(dǎo)致的問(wèn)題

在同一個(gè)應(yīng)用程序或者不同應(yīng)用程序中的多個(gè)事務(wù)在同一個(gè)數(shù)據(jù)集上并發(fā)執(zhí)行時(shí),可能會(huì)出現(xiàn)許多意外的問(wèn)題。

并發(fā)事務(wù)所導(dǎo)致的問(wèn)題可以分為以下三類:

① 臟讀:臟讀發(fā)生在一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫(xiě)但尚未提交的數(shù)據(jù)時(shí)。如果改寫(xiě)在稍后被回滾了,那么第一個(gè)事務(wù)獲取的數(shù)據(jù)就是無(wú)效的。

② 不可重復(fù)讀:不可重復(fù)讀發(fā)生在一個(gè)事務(wù)執(zhí)行相同的查詢兩次或兩次以上,但是每次都得到不同的數(shù)據(jù)時(shí)。這通常是因?yàn)榱硪粋€(gè)并發(fā)事務(wù)在兩次查詢期間更新了數(shù)據(jù)

③ 幻讀:幻讀與不可重復(fù)讀類似。它發(fā)生在一個(gè)事務(wù)(T1)讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時(shí)。在隨后的查詢中,第一個(gè)事務(wù)(T1)就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄

代碼示例

首先是數(shù)據(jù)庫(kù)表:

包括book(isbn, book_name, price),account(username, balance),book_stock(isbn, stock)

然后是使用的類:

BookShopDao

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;

public interface BookShopDao {
    //根據(jù)書(shū)號(hào)獲取書(shū)的單價(jià)
    public int findBookPriceByIsbn(String isbn);
    //更新書(shū)的庫(kù)存,使書(shū)號(hào)對(duì)應(yīng)的庫(kù)存-1
    public void updateBookStock(String isbn);
    //更新用戶的賬戶余額:使username的balcance-price
    public void updateUserAccount(String username, int price);
   
}

BookShopDaoImpl

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {

    @Autowired
    private JdbcTemplate JdbcTemplate;
   
    @Override
    public int findBookPriceByIsbn(String isbn) {
        String sql = "SELECT price FROM book WHERE isbn = ?";
       
        return JdbcTemplate.queryForObject(sql, Integer.class, isbn);
    }

    @Override
    public void updateBookStock(String isbn) {
        //檢查書(shū)的庫(kù)存是否足夠,若不夠,則拋出異常
        String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
        int stock = JdbcTemplate.queryForObject(sql2, Integer.class, isbn);
        if (stock == 0) {
            throw new BookStockException("庫(kù)存不足!");
        }
        String sql = "UPDATE book_stock SET stock = stock - 1 WHERE isbn = ?";
        JdbcTemplate.update(sql, isbn);
    }

    @Override
    public void updateUserAccount(String username, int price) {
        //檢查余額是否不足,若不足,則拋出異常
        String sql2 = "SELECT balance FROM account WHERE username = ?";
        int balance = JdbcTemplate.queryForObject(sql2, Integer.class, username);
        if (balance < price) {
            throw new UserAccountException("余額不足!");
        }       
        String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
        JdbcTemplate.update(sql, price, username);
    }

}

BookShopService

復(fù)制代碼 代碼如下:
package com.yl.spring.tx;
public interface BookShopService {
     public void purchase(String username, String isbn);
}

BookShopServiceImpl

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {

    @Autowired
    private BookShopDao bookShopDao;
   
    /**
     * 1.添加事務(wù)注解
     * 使用propagation 指定事務(wù)的傳播行為,即當(dāng)前的事務(wù)方法被另外一個(gè)事務(wù)方法調(diào)用時(shí)如何使用事務(wù)。
     * 默認(rèn)取值為REQUIRED,即使用調(diào)用方法的事務(wù)
     * REQUIRES_NEW:使用自己的事務(wù),調(diào)用的事務(wù)方法的事務(wù)被掛起。
     *
     * 2.使用isolation 指定事務(wù)的隔離級(jí)別,最常用的取值為READ_COMMITTED
     * 3.默認(rèn)情況下 Spring 的聲明式事務(wù)對(duì)所有的運(yùn)行時(shí)異常進(jìn)行回滾,也可以通過(guò)對(duì)應(yīng)的屬性進(jìn)行設(shè)置。通常情況下,默認(rèn)值即可。
     * 4.使用readOnly 指定事務(wù)是否為只讀。 表示這個(gè)事務(wù)只讀取數(shù)據(jù)但不更新數(shù)據(jù),這樣可以幫助數(shù)據(jù)庫(kù)引擎優(yōu)化事務(wù)。若真的是一個(gè)只讀取數(shù)據(jù)庫(kù)值得方法,應(yīng)設(shè)置readOnly=true
     * 5.使用timeOut 指定強(qiáng)制回滾之前事務(wù)可以占用的時(shí)間。
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW,
            isolation=Isolation.READ_COMMITTED,
            noRollbackFor={UserAccountException.class},
            readOnly=true, timeout=3)
    @Override
    public void purchase(String username, String isbn) {
        //1.獲取書(shū)的單價(jià)
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.更新書(shū)的庫(kù)存
        bookShopDao.updateBookStock(isbn);
        //3.更新用戶余額
        bookShopDao.updateUserAccount(username, price);;
    }
}

BookStockException

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;
public class BookStockException extends RuntimeException {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public BookStockException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public BookStockException(String arg0, Throwable arg1, boolean arg2,
            boolean arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

    public BookStockException(String arg0, Throwable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public BookStockException(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public BookStockException(Throwable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }
}

UserAccountException

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;
public class UserAccountException extends RuntimeException {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public UserAccountException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public UserAccountException(String arg0, Throwable arg1, boolean arg2,
            boolean arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

    public UserAccountException(String arg0, Throwable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public UserAccountException(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public UserAccountException(Throwable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }
}

Cashier

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;
import java.util.List;
public interface Cashier {
    public void checkout(String username, List<String>isbns);
}

CashierImpl。CashierImpl.checkout和bookShopService.purchase聯(lián)合測(cè)試了事務(wù)的傳播行為

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("cashier")
public class CashierImpl implements Cashier {
    @Autowired
    private BookShopService bookShopService;
   
    @Transactional
    @Override
    public void checkout(String username, List<String> isbns) {
        for(String isbn : isbns) {
            bookShopService.purchase(username, isbn);
        }
    }
}

測(cè)試類:

復(fù)制代碼 代碼如下:

package com.yl.spring.tx;

import java.util.Arrays;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTransitionTest {
   
    private ApplicationContext ctx = null;
    private BookShopDao bookShopDao = null;
    private BookShopService bookShopService = null;
    private Cashier cashier = null;
    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        bookShopDao = ctx.getBean(BookShopDao.class);
        bookShopService = ctx.getBean(BookShopService.class);
        cashier = ctx.getBean(Cashier.class);
    }
   
    @Test
    public void testBookShopDaoFindPriceByIsbn() {
        System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
    }

    @Test
    public void testBookShopDaoUpdateBookStock(){
        bookShopDao.updateBookStock("1001");
    }
   
    @Test
    public void testBookShopDaoUpdateUserAccount(){
        bookShopDao.updateUserAccount("AA", 100);
    }
    @Test
    public void testBookShopService(){
        bookShopService.purchase("AA", "1001");
    }
   
    @Test
    public void testTransactionPropagation(){
        cashier.checkout("AA", Arrays.asList("1001", "1002"));
    }
}

希望本文所述對(duì)大家的Spring程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • java 之JNA中的Memory和Pointer的使用方法

    java 之JNA中的Memory和Pointer的使用方法

    這篇文章主要介紹了java 之JNA中的Memory和Pointer的使用方法,文章基于Java的相關(guān)自來(lái)哦展開(kāi)對(duì)Pointer和Memory的使用介紹,需要的小伙伴可以參考一下
    2022-04-04
  • spring?boot配置dubbo方式(properties)

    spring?boot配置dubbo方式(properties)

    這篇文章主要介紹了spring?boot配置dubbo方式(properties),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • 詳解Java中跳躍表的原理和實(shí)現(xiàn)

    詳解Java中跳躍表的原理和實(shí)現(xiàn)

    跳躍表(Skip list)是有序鏈表的擴(kuò)展,簡(jiǎn)稱跳表,它在原有的有序鏈表上增加了多級(jí)索引,通過(guò)索引來(lái)實(shí)現(xiàn)快速查找,實(shí)質(zhì)上是一種可以進(jìn)行二分查找的有序鏈表。本文主要為大家介紹了跳躍表的原理和實(shí)現(xiàn),需要的可以參考一下
    2022-12-12
  • 如何解決HttpServletRequest.getInputStream()多次讀取問(wèn)題

    如何解決HttpServletRequest.getInputStream()多次讀取問(wèn)題

    這篇文章主要介紹了如何解決HttpServletRequest.getInputStream()多次讀取問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • idea創(chuàng)建SpringBoot項(xiàng)目及注解配置相關(guān)應(yīng)用小結(jié)

    idea創(chuàng)建SpringBoot項(xiàng)目及注解配置相關(guān)應(yīng)用小結(jié)

    Spring Boot是Spring社區(qū)發(fā)布的一個(gè)開(kāi)源項(xiàng)目,旨在幫助開(kāi)發(fā)者快速并且更簡(jiǎn)單的構(gòu)建項(xiàng)目,Spring Boot框架,其功能非常簡(jiǎn)單,便是幫助我們實(shí)現(xiàn)自動(dòng)配置,本文給大家介紹idea創(chuàng)建SpringBoot項(xiàng)目及注解配置相關(guān)應(yīng)用,感興趣的朋友跟隨小編一起看看吧
    2023-11-11
  • java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別

    java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別

    這篇文章主要介紹了java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別的相關(guān)資料,本文主要說(shuō)明兩者的區(qū)別以防大家混淆概念,需要的朋友可以參考下
    2017-08-08
  • Spring Boot console log 格式自定義方式

    Spring Boot console log 格式自定義方式

    這篇文章主要介紹了Spring Boot console log 格式自定義方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 全面解析Java中的HashMap類

    全面解析Java中的HashMap類

    HashMap類為Java提供了鍵值對(duì)應(yīng)的map類型,本文將從源碼角度全面解析Java中的HashMap類,同時(shí)包括其各種常用操作方法等,歡迎參考與借鑒
    2016-05-05
  • Java基礎(chǔ)之如何學(xué)好Java

    Java基礎(chǔ)之如何學(xué)好Java

    這篇文章已經(jīng)是有數(shù)年“網(wǎng)齡”的老文,不過(guò)在今天看來(lái)仍然經(jīng)典。如何學(xué)習(xí)java?本篇文章可以說(shuō)也是面對(duì)編程初學(xué)者的一篇指導(dǎo)文章,其中對(duì)于如何學(xué)習(xí)Java的步驟的介紹,很多也適用于開(kāi)發(fā)領(lǐng)域其他技能的學(xué)習(xí)。
    2014-10-10
  • java父子節(jié)點(diǎn)parentid樹(shù)形結(jié)構(gòu)數(shù)據(jù)的規(guī)整

    java父子節(jié)點(diǎn)parentid樹(shù)形結(jié)構(gòu)數(shù)據(jù)的規(guī)整

    這篇文章主要介紹了java父子節(jié)點(diǎn)parentid樹(shù)形結(jié)構(gòu)數(shù)據(jù)的規(guī)整,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評(píng)論