亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Spring中的事務管理實例詳解

2019-11-26 15:21:24
字體:
來源:轉載
供稿:網友

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

事務簡介:

事務管理是企業級應用程序開發中必不可少的技術,用來確保數據的完整性和一致性

事務就是一系列的動作,它們被當作一個單獨的工作單元。這些動作要么全部完成,要么全部不起作用

事務的四個關鍵屬性(ACID)

① 原子性(atomicity):事務室一個原子操作,有一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用
② 一致性(consistency):一旦所有事務動作完成,事務就被提交。數據和資源就處于一種滿足業務規則的一致性狀態中
③ 隔離性(isolation):可能有許多事務會同時處理相同的數據,因此每個事物都應該與其他事務隔離開來,防止數據損壞
④ 持久性(durability):一旦事務完成,無論發生什么系統錯誤,它的結果都不應該受到影響。通常情況下,事務的結果被寫到持久化存儲器中

Spring中的事務管理

作為企業級應用程序框架,Spring在不同的事務管理API之上定義了一個抽象層。而應用程序開發人員不必了解底層的事務管理API,就可以使用Spring的事務管理機制。

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

編程式事務管理:將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾,在編程式事務中,必須在每個業務操作中包含額外的事務管理代碼

聲明式事務管理:大多數情況下比編程式事務管理更好用。它將事務管理代碼從業務方法中分離出來,以聲明的方式來實現事務管理。事務管理作為一種橫切關注點,可以通過AOP方法模塊化。Spring通過Spring AOP框架支持聲明式事務管理。

Spring事務的傳播屬性:

當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。

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

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

其中PROPAGATION_REQUIRED為默認的傳播屬性

并發事務所導致的問題

在同一個應用程序或者不同應用程序中的多個事務在同一個數據集上并發執行時,可能會出現許多意外的問題。

并發事務所導致的問題可以分為以下三類:

① 臟讀:臟讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍后被回滾了,那么第一個事務獲取的數據就是無效的。

② 不可重復讀:不可重復讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因為另一個并發事務在兩次查詢期間更新了數據

③ 幻讀:幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄

代碼示例

首先是數據庫表:

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

然后是使用的類:

BookShopDao

復制代碼 代碼如下:

package com.yl.spring.tx;

public interface BookShopDao {
    //根據書號獲取書的單價
    public int findBookPriceByIsbn(String isbn);
    //更新書的庫存,使書號對應的庫存-1
    public void updateBookStock(String isbn);
    //更新用戶的賬戶余額:使username的balcance-price
    public void updateUserAccount(String username, int price);
   
}

BookShopDaoImpl

復制代碼 代碼如下:

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) {
        //檢查書的庫存是否足夠,若不夠,則拋出異常
        String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
        int stock = JdbcTemplate.queryForObject(sql2, Integer.class, isbn);
        if (stock == 0) {
            throw new BookStockException("庫存不足!");
        }
        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

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

BookShopServiceImpl

復制代碼 代碼如下:

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.添加事務注解
     * 使用propagation 指定事務的傳播行為,即當前的事務方法被另外一個事務方法調用時如何使用事務。
     * 默認取值為REQUIRED,即使用調用方法的事務
     * REQUIRES_NEW:使用自己的事務,調用的事務方法的事務被掛起。
     *
     * 2.使用isolation 指定事務的隔離級別,最常用的取值為READ_COMMITTED
     * 3.默認情況下 Spring 的聲明式事務對所有的運行時異常進行回滾,也可以通過對應的屬性進行設置。通常情況下,默認值即可。
     * 4.使用readOnly 指定事務是否為只讀。 表示這個事務只讀取數據但不更新數據,這樣可以幫助數據庫引擎優化事務。若真的是一個只讀取數據庫值得方法,應設置readOnly=true
     * 5.使用timeOut 指定強制回滾之前事務可以占用的時間。
     */
    @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.獲取書的單價
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.更新書的庫存
        bookShopDao.updateBookStock(isbn);
        //3.更新用戶余額
        bookShopDao.updateUserAccount(username, price);;
    }
}

BookStockException

復制代碼 代碼如下:

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

復制代碼 代碼如下:

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

復制代碼 代碼如下:

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聯合測試了事務的傳播行為

復制代碼 代碼如下:

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);
        }
    }
}

測試類:

復制代碼 代碼如下:

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"));
    }
}

希望本文所述對大家的Spring程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
26uuu国产精品视频| 不卡av电影在线观看| 日韩欧美中文免费| 久久精品亚洲一区| 97视频网站入口| 日本精品一区二区三区在线| 精品欧美一区二区三区| 亚洲无av在线中文字幕| 亚洲国产精品悠悠久久琪琪| 欧美成人午夜视频| 国产亚洲精品久久久久久牛牛| 日韩精品久久久久久久玫瑰园| 国产精品一区二区在线| 久久久国产精品免费| 国产一区二区美女视频| 欧美午夜精品久久久久久浪潮| 久热精品在线视频| 欧美一区二区视频97| 中文在线资源观看视频网站免费不卡| 欧美极品美女电影一区| 欧美一级bbbbb性bbbb喷潮片| 亚洲午夜性刺激影院| 国产主播精品在线| 97免费视频在线播放| 日韩精品在线观看一区| 日韩欧美在线中文字幕| 日韩美女在线播放| 国产精品av免费在线观看| 大量国产精品视频| 国产主播精品在线| 欧美重口另类videos人妖| 国产精品一区二区久久久久| 国产成人综合av| 91久久精品一区| 国产精品igao视频| 中文字幕久久久av一区| 日韩中文字幕在线| 国产精品白丝av嫩草影院| 欧美性猛交xxxx富婆弯腰| 国产精品视频永久免费播放| 91精品久久久久| 国产精品偷伦免费视频观看的| 2019亚洲日韩新视频| 在线观看日韩视频| 超碰91人人草人人干| 成人中文字幕+乱码+中文字幕| 高跟丝袜一区二区三区| 国内精品小视频在线观看| 亚洲天堂第二页| 亚洲精品视频久久| 国产剧情日韩欧美| 久久精品国产综合| 亚洲成人教育av| 6080yy精品一区二区三区| 国产精品美女网站| 亚洲日韩欧美视频一区| 国产精品日日做人人爱| 久久久精品国产一区二区| 国产欧美日韩中文字幕| 少妇av一区二区三区| 精品国偷自产在线视频99| 亚洲午夜精品久久久久久久久久久久| 久久国产天堂福利天堂| 欧美大片欧美激情性色a∨久久| 亚洲欧美日韩图片| 成人国产精品av| 国产精品美女久久久久久免费| 这里只有精品在线播放| 亚洲国产精品国自产拍av秋霞| 亚洲精品国产精品国自产在线| 精品成人乱色一区二区| 欧美性极品xxxx娇小| 亚洲视频电影图片偷拍一区| 91国产视频在线播放| 7777kkkk成人观看| 在线看日韩欧美| 正在播放欧美视频| 中文字幕日韩在线视频| 亚洲成人精品久久久| 亚洲sss综合天堂久久| 久久久久国产视频| 国产精品高潮呻吟久久av无限| 日韩在线激情视频| 日韩大片在线观看视频| 欧美性猛交xxxx富婆弯腰| 国产精选久久久久久| 亚洲片国产一区一级在线观看| 日韩欧美成人网| 久久精品电影网站| 亚洲欧美国产精品va在线观看| 日韩电视剧免费观看网站| 国产精品久久久久久久久免费| 欧美性高跟鞋xxxxhd| 久久久久久久久中文字幕| 日韩影视在线观看| 成人久久精品视频| 国产专区精品视频| 国产不卡精品视男人的天堂| 日韩人体视频一二区| 国内精品模特av私拍在线观看| 国产mv久久久| 一区二区三区视频观看| 久久久亚洲欧洲日产国码aⅴ| 日韩美女福利视频| 91久久精品国产91久久| 国产精品偷伦免费视频观看的| 国产欧美一区二区三区视频| 亚洲欧美变态国产另类| 国产视频亚洲视频| 日韩二区三区在线| 亚洲男人第一网站| 欧美性猛交xxx| 亚洲精品美女免费| 成人美女免费网站视频| 亚洲直播在线一区| 国产精品情侣自拍| 国产精品夜间视频香蕉| 国产精品永久免费观看| 国产成人精品日本亚洲专区61| 色香阁99久久精品久久久| 国产成人在线视频| 国产69精品久久久久9| 色婷婷av一区二区三区久久| 日本久久亚洲电影| 性欧美激情精品| 欧美日韩国产综合视频在线观看中文| 亚洲精品有码在线| 91在线播放国产| 中文字幕av一区二区三区谷原希美| 国产日韩欧美日韩大片| 欧美大片免费观看| 欧美日韩免费在线| 亚洲精品视频二区| 亚洲一区二区三区在线免费观看| 国产精品海角社区在线观看| 久久国产视频网站| 日韩成人av网| 欧美亚洲第一区| 久久久久久亚洲精品| 成人午夜在线观看| 81精品国产乱码久久久久久| www.久久久久久.com| 国产美女精彩久久| 欧美日韩国产页| 亚州欧美日韩中文视频| 97超级碰碰人国产在线观看| 日韩免费不卡av| 国产精品吹潮在线观看| 97精品国产97久久久久久春色| 黑人狂躁日本妞一区二区三区| 亚洲午夜久久久影院| 亚洲美女又黄又爽在线观看| 欧美大片大片在线播放| 中文字幕精品一区久久久久| 久久九九国产精品怡红院| 日韩电影第一页| 久久天天躁狠狠躁夜夜爽蜜月| 亚洲国产欧美一区二区丝袜黑人| 亚洲国产精品悠悠久久琪琪| 96国产粉嫩美女| 91精品中文在线| 成人在线精品视频| 中文字幕日韩精品在线| 国产精品嫩草影院一区二区|