Spring学習ノート---事務管理

18220 ワード

Springトランザクションの宣言
スプリングがトランザクションを使用する前に、まず手動でトランザクションを書く方法を見てみましょう.
需要:book shopの管理実現
dataSource.properties(データソース情報)
jdbc.user = root
jdbc.password =123456
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.jdbcUrl = jdbc:mysql:///spring2

jdbc.initPoolSize=5
jdbc.maxPoolSize=10

applicationContext.xml(Springのプロファイル)


    
    
    
    
    
    
        
        
        
        
        
        
    
    
    
        
    

    
    
        
    
BookShopDao.JAva(書店データベース操作インタフェース)
package cn.limbo.spring.tx;

/**
 * Created by Limbo on 16/7/15.
 */
public interface BookShopDao {
    //          
    public int findBookPriceByIsbn(int isbn);

    //      ,         - 1
    public void updateBookStock(int isbn);

    //         : userName balance - price
    public void updateUserAccount(String userName,int price);
}

BookShopDaoImpl.JAva(書店データベース操作実装)
package cn.limbo.spring.tx;

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

/**
 * Created by Limbo on 16/7/15.
 */
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;


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

    }

    @Override
    public void updateBookStock(int 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.JAva(書店サービスインタフェース)
package cn.limbo.spring.tx;

/**
 * Created by Limbo on 16/7/15.
 */
public interface BookShopService {
    public void purchase(String userName,int price);
}
BookShopServiceImpl.JAva(書店サービス実現)
package cn.limbo.spring.tx;

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

/**
 * Created by Limbo on 16/7/15.
 */
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    @Override
    public void purchase(String userName, int isbn) {
        //1.      
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.    
        bookShopDao.updateBookStock(isbn);
        //3.      
        bookShopDao.updateUserAccount(userName,price);
    }
}

BookStockException.JAva(ライブラリ格納異常)
package cn.limbo.spring.tx;

/**
 * Created by Limbo on 16/7/15.
 */
public class BookStockException extends RuntimeException {
    public BookStockException() {
        super();
    }

    public BookStockException(String message) {
        super(message);
    }

    public BookStockException(String message, Throwable cause) {
        super(message, cause);
    }

    public BookStockException(Throwable cause) {
        super(cause);
    }

    protected BookStockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
UserAccountException.JAva(ユーザ残高異常)
package cn.limbo.spring.tx;

/**
 * Created by Limbo on 16/7/15.
 */
public class UserAccountException extends RuntimeException {
    public UserAccountException() {
        super();
    }

    public UserAccountException(String message) {
        super(message);
    }

    public UserAccountException(String message, Throwable cause) {
        super(message, cause);
    }

    public UserAccountException(Throwable cause) {
        super(cause);
    }

    protected UserAccountException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
SpringTransactionTest.JAva(テスト方法)
package cn.limbo.spring.tx;

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

/**
 * Created by Limbo on 16/7/15.
 */
public class SpringTransactionTest {

    private static ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    private static BookShopDao bookShopDao = (BookShopDao) ctx.getBean("bookShopDao");
    private static BookShopService bookShopService = (BookShopService) ctx.getBean("bookShopService");
    public static void testBookShopDaoFindPriceByIsbn(int isbn)
    {
        System.out.println(bookShopDao.findBookPriceByIsbn(isbn));
    }

    public static void testBookShopDaoUpdateStock(int isbn)
    {
        bookShopDao.updateBookStock(isbn);
    }

    public static void testBookShopUpdateUserAccount(String name,int price)
    {
        bookShopDao.updateUserAccount(name,price);
    }

    public static void testBookShopService(String userName,int isbn)
    {
        bookShopService.purchase(userName,isbn);
    }

    public static void main(String[] args) {
        testBookShopService("AA",1001);
    }
}

上のtestBookShopServiceという方法は私たちがトランザクションを実行する方法ですが、この方法はトランザクションのACIDの原則を満たしていないことがわかります.残高が不足している場合、本の貯蔵数が減少します.このときspringの事務マネージャを使うべきです.
アプリケーションContext.xmlトランザクションマネージャを追加し、追加後は次のようにします.


    
    
    
    
    
    
        
        
        
        
        
        
    
    
    
        
    

    
    
        
    

    
    
        
    

    
    

注意して、txのネーミングスペースは間違っていないでください.最初は私が間違っていました.それからtransaction-managerが現れませんでした.うんざりしました.
そしてトランザクションを実現する方法に@Transactional注記を付ければ良い、書き換えたBookShopServiceImpl.JAvaは以下の通りです
package cn.limbo.spring.tx;

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

/**
 * Created by Limbo on 16/7/15.
 */
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    @Transactional    //      
    @Override
    public void purchase(String userName, int isbn) {
        //1.      
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.    
        bookShopDao.updateBookStock(isbn);
        //3.      
        bookShopDao.updateUserAccount(userName,price);
    }
}
これでSpring宣言トランザクションの方法が実現しました
トランザクションの伝播動作
トランザクション・メソッドが別のトランザクション・メソッドを呼び出すときに表示されるプロパティを指します.例えば、ホテルに行って食事をしたり、知り合いに会ったり、知り合いに食事を呼んだりします.このとき、知り合いと一緒に食べるか、自分で食べるかの2つの選択肢があります.上记の表现の中で、新しい事务は私で、古い事务は知人で、知人と一绪に食事をするのは元の事务に沿って、自分で食事をするのは新しい事务を创建して、下でコードを见ます
新しいインタフェースとクラス
Cashier.java
package cn.limbo.spring.tx;

import java.util.List;

/**
 * Created by Limbo on 16/7/16.
 */
public interface Cashier {
    public void checkOut(String userName,List isbns);
}
CashierImpl.java
package cn.limbo.spring.tx;

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

import java.util.List;

/**
 * Created by Limbo on 16/7/16.
 */

@Service("cashier")
public class CashierImpl implements Cashier{

    @Autowired
    private BookShopService bookShopService;

    @Transactional
    @Override
    //  ,       
    public void checkOut(String userName, List isbns) {
        for(Integer isbn : isbns)
        {
            bookShopService.purchase(userName,isbn);
        }
    }
}

Test.java
public static void testTransactionalPropagation(String userName, List isbns)
    {
        cashier.checkOut(userName,isbns);
    }

    public static void main(String[] args) {
        testTransactionalPropagation("AA", Arrays.asList(1001,1002));
    }

この時、私たちはbookShopServicesを発見しました.purchaseはトランザクションですが、checkOutもトランザクションです.このとき実行するとどのような結果になりますか(bookShopService)
.purchase()ですか、それとも上と同じですか.
このとき、残高が1001を買うのに十分だが1002を買うことができない場合、事務は自動的にロールバックし、2冊の本を買わない場合にロールバックすることに気づいた.このときcheckOutは元の事務を使っているので、何の変化もない.残高が1001しか買えないが1002を買うのに十分でない場合、bookShopServicesを買うことができる.purchase上の@Transactionalを@Transactional(propagation=Propagation.REQUIRES_NEW)に変更すれば、修正後のbooShopServices.JAvaは以下の通りです
package cn.limbo.spring.tx;

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

/**
 * Created by Limbo on 16/7/15.
 */
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    //      
    //  propagation         ,                      
    //      ,     REQUIRED,          
    //       REQUIRES_NEW:         ,          
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void purchase(String userName, int isbn) {
        //1.      
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.    
        bookShopDao.updateBookStock(isbn);
        //3.      
        bookShopDao.updateUserAccount(userName,price);
    }
}
propagationのすべての属性を添付します.
PROPAGATION_REQUIRD--現在のトランザクションをサポートし、現在トランザクションがない場合は新規トランザクションを作成します.これは最も一般的な選択です. 
PROPAGATION_REQUIRES_NEW--新しいトランザクションを作成します.現在トランザクションが存在する場合は、現在のトランザクションを保留します.
PROPAGATION_SUPPORTS--現在のトランザクションをサポートし、現在トランザクションがない場合は非トランザクションで実行します. 
PROPAGATION_MANDATORY--現在のトランザクションをサポートし、現在トランザクションがない場合は例外を放出します. 
 
PROPAGATION_NOT_SUPPORTED-現在トランザクションが存在する場合は、非トランザクションでアクションを実行します. 
PROPAGATION_NEVER---非トランザクションで実行され、現在トランザクションが存在する場合は例外が放出されます. 
最初の2つが最もよく使われています
トランザクションの独立性、ロールバック、読み取り専用、期限切れ
一言が合わなくて、直接コードを貼って、要点は注釈を書きます
package cn.limbo.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;

/**
 * Created by Limbo on 16/7/15.
 */
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{

    @Autowired
    private BookShopDao bookShopDao;

    //      
    //1.  propagation         ,                      
    //        ,     REQUIRED,          
    //         REQUIRES_NEW:         ,          
    //2.  isolation         ,     Isolation.READ_COMMITTED
    //3.     ,Spring                   ,              
    //       ,      
    //  noRollbackFor = {UserAccountException.class}               ,     ,    
    //4.  readOnly         ,                 ,             
    //                   ,    readOnly=true,     false,     
    //5.  timeout                 ,    timeout=3,     3      ,        
//    @Transactional(propagation = Propagation.REQUIRES_NEW ,
//            isolation = Isolation.READ_COMMITTED ,
//            noRollbackFor = {UserAccountException.class})
    @Transactional(propagation = Propagation.REQUIRES_NEW ,
            isolation = Isolation.READ_COMMITTED ,
            readOnly = false ,
            timeout = 3) //timeout     
    @Override
    public void purchase(String userName, int isbn) {
        //1.      
        int price = bookShopDao.findBookPriceByIsbn(isbn);
        //2.    
        bookShopDao.updateBookStock(isbn);
        //3.      
        bookShopDao.updateUserAccount(userName,price);
    }
}

トランザクションのxml構成方法
1.通常のコントローラ、サービス、daoのbeanを配置する.

    
        
    
    
    
        
    
    
    
        
    

2.トランザクションマネージャbeanの構成

    
        
    

3.txネーミングスペースの導入
xmlns:tx="http://www.springframework.org/schema/tx"

4.トランザクションの各プロパティの構成(メソッド名はワイルドカード*を使用できます)

    
        
            
            
                        
                        
        
    

5.aopネーミングスペースの導入
xmlns:aop="http://www.springframework.org/schema/aop"