5

Spring トランザクションの分離レベルを理解しようとしています。これが私が使用している例です:

@Component
public class BookShop {

    private Object lockObj = new Object();

    @Autowired
    private BookDao bookDao;

    @Transactional
    public void increaseStock(int isbn, int increment){
        String threadName = Thread.currentThread().getName();
        synchronized (lockObj) {
            Book book = bookDao.findByIsbn(isbn);
            System.out.println(threadName+" about to increment the stock");
            bookDao.updateStock(book, 5);
        }
        System.out.println(threadName+" has increased the stock ");
        sleep(threadName);
        System.out.println(threadName+" rolled back stock");
        throw new RuntimeException("Stock increased by mistake");
    }

    @Transactional
    public int checkStock(int isbn){
        int stock = 0;
        String threadName = Thread.currentThread().getName();
        synchronized (lockObj) {
            System.out.println(threadName+" checking for the stock");
            stock = bookDao.getStock(isbn);
        }
        System.out.println(threadName+": Stock is: "+stock);
        sleep(threadName);
        return stock;
    }

    private void sleep(String threadName){
        System.out.println(threadName+" sleeping");
        try{
            Thread.sleep(1000);
        }catch (InterruptedException e) {
        }
        System.out.println(threadName+" wakeup!");
    }

}

そして、これは私が上記を呼び出す方法です:

public void testIsolationLevels(final BookShop bookShop, final int isbn){
        Thread t1 = new Thread(){
            public void run() {
                bookShop.increaseStock(isbn, 5);
            };
        };
        t1.setPriority(Thread.MAX_PRIORITY);
        t1.start();

        Thread t2 = new Thread(){
            public void run() {
                bookShop.checkStock(isbn);
            };
        };
        t2.setPriority(Thread.MIN_PRIORITY);
        t2.start();
    }

そして、ここにトランザクション構成があります:

<tx:advice id="bookTxn" transaction-manager="transactionManager">
        <tx:attributes> 
            <tx:method name="updateStock" isolation="READ_UNCOMMITTED"/>
            <tx:method name="getStock" isolation="READ_UNCOMMITTED"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut expression="execution(* com.pramati.springIdol.dao.BookDao+.*(..))" id="bookPC"/>
        <aop:advisor advice-ref="bookTxn"  pointcut-ref="bookPC"/>
    </aop:config>

しかし、この例を実行すると、次のような o/p が得られます。

Thread-2 about to increment the stock// Initially it is 99
Thread-2 has increased the stock // Now it is 104(99+5)
Thread-2 sleeping
Thread-3 checking for the stock
Thread-3: Stock is: 99//Why is it not 104 even if isolation level is read_uncommitted??
Thread-3 sleeping
Thread-2 wakeup!
Thread-2 rolled back stock
Thread-3 wakeup!
Exception in thread "Thread-2" java.lang.RuntimeException: Stock increased by mistake

Thread-3 は更新された値を読み取ることができると思いました。そうではありません。誰かが私が間違っているところを教えてもらえますか?

前もって感謝します!

4

1 に答える 1

3

ここでの問題は、別のトランザクション メソッド (BookShop のメソッド) から DAO のトランザクション メソッドを呼び出していることです。

BookShop のメソッドの分離レベルを指定していないため、デフォルトの分離レベルは Isolation.READ_COMMITTED です。

また、Dao のメソッドの伝播動作を指定していないことに注意してください。デフォルトの動作は Propagation.REQUIRED です。したがって、dao メソッドは BookShop のものと同じトランザクションを使用します。したがって、 Isolation.READ_COMMITTED の分離がトランザクションに適用されます。

解決策: BookShop メソッドの分離レベルを READ_UNCOMMITTED に指定する

于 2012-06-21T15:02:53.573 に答える