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

Spring 多線程事務(wù)控制的實(shí)踐

 更新時(shí)間:2023年09月16日 15:26:29   作者:qq_35987023  
本文主要介紹了Spring 多線程事務(wù)控制的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在Java多線程事務(wù)控制中,有一些注意事項(xiàng)和實(shí)例可以幫助你更好地理解和應(yīng)用。

注意事項(xiàng)

  • 確保線程安全:在多線程環(huán)境下,確保代碼是線程安全的。這可以通過使用synchronized關(guān)鍵字、Lock接口或Atomic類來實(shí)現(xiàn)。
  • 事務(wù)的隔離級(jí)別:根據(jù)需要選擇適當(dāng)?shù)氖聞?wù)隔離級(jí)別,以避免并發(fā)問題,例如臟讀、不可重復(fù)讀和幻讀。
  • 事務(wù)的傳播行為:了解事務(wù)的傳播行為,例如事務(wù)的提交和回滾如何影響其他事務(wù)。
  • 異常處理:在多線程環(huán)境下處理異常時(shí),需要特別小心。確保捕獲和處理所有異常,并正確地處理事務(wù)回滾。

spring事務(wù)隔離級(jí)別

Java Spring框架提供了一種方便的方式來管理數(shù)據(jù)庫事務(wù),它支持多種事務(wù)隔離級(jí)別。事務(wù)隔離級(jí)別決定了事務(wù)在并發(fā)執(zhí)行時(shí)的隔離程度,包括對(duì)其他事務(wù)的可見性和可能出現(xiàn)的并發(fā)問題。

以下是Spring框架支持的事務(wù)隔離級(jí)別及其詳細(xì)說明:

  • ISOLATION_DEFAULT(默認(rèn)):這是系統(tǒng)的默認(rèn)隔離級(jí)別。根據(jù)具體數(shù)據(jù)庫來定義,大多數(shù)數(shù)據(jù)庫默認(rèn)級(jí)別是可重復(fù)讀。
  • ISOLATION_READ_UNCOMMITTED(讀未提交):在這個(gè)級(jí)別,一個(gè)事務(wù)可以看到其他未提交事務(wù)的變動(dòng)。這種級(jí)別可以導(dǎo)致臟讀、不可重復(fù)讀和幻讀的問題。
  • ISOLATION_READ_COMMITTED(讀提交):在這個(gè)級(jí)別,一個(gè)事務(wù)只能看到其他事務(wù)已經(jīng)提交的變動(dòng)。這種級(jí)別可以避免臟讀問題,但可能會(huì)出現(xiàn)不可重復(fù)讀和幻讀的問題。
  • ISOLATION_REPEATABLE_READ(可重復(fù)讀):在這個(gè)級(jí)別,同一事務(wù)中多次讀取的數(shù)據(jù)是一致的。這種級(jí)別可以避免臟讀和不可重復(fù)讀的問題,但可能會(huì)出現(xiàn)幻讀的問題。
  • ISOLATION_SERIALIZABLE(可串行化):這是最高的事務(wù)隔離級(jí)別。在這個(gè)級(jí)別,事務(wù)串行化順序執(zhí)行,可以避免臟讀、不可重復(fù)讀和幻讀的問題。但是這種隔離級(jí)別效率低下,因?yàn)槭聞?wù)通常需要等待前一個(gè)事務(wù)完成,才能繼續(xù)執(zhí)行。

Spring事務(wù)的默認(rèn)隔離級(jí)別與數(shù)據(jù)庫一致

在Spring中,可以通過以下方式設(shè)置事務(wù)的隔離級(jí)別:

@Transactional(isolation = Isolation.READ_COMMITTED)  
public void someMethod() {  
    // some code  
}

在上述代碼中,@Transactional注解指定了事務(wù)的隔離級(jí)別為READ_COMMITTED。注意,雖然可以使用其他隔離級(jí)別,但并不是所有數(shù)據(jù)庫都支持所有的隔離級(jí)別。使用哪種隔離級(jí)別取決于你的具體需求和數(shù)據(jù)庫的能力。

spring事務(wù)傳播行為

Java Spring框架中的事務(wù)傳播行為是指在一個(gè)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),如何處理事務(wù)的傳播。事務(wù)傳播行為定義了在一個(gè)方法中調(diào)用另一個(gè)方法時(shí),事務(wù)應(yīng)該如何啟動(dòng)、提交或回滾。

以下是Spring框架支持的事務(wù)傳播行為及其詳細(xì)說明:

  • PROPAGATION_REQUIRED(必需):如果當(dāng)前存在一個(gè)事務(wù),那么就加入這個(gè)事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。
  • PROPAGATION_SUPPORTS(支持):支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
  • PROPAGATION_MANDATORY(強(qiáng)制):使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
  • PROPAGATION_REQUIRES_NEW(新建):新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NOT_SUPPORTED(不支持):以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
  • PROPAGATION_NEVER(從不):以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),拋出異常。
  • PROPAGATION_NESTED(嵌套):如果當(dāng)前存在一個(gè)事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則進(jìn)行與PROPAGATION_REQUIRED類似的操作。

在Spring中,可以通過以下方式設(shè)置事務(wù)的傳播行為:

@Transactional(propagation = Propagation.REQUIRES_NEW)  
public void someMethod() {  
    // some code  
}

在上述代碼中,@Transactional注解指定了事務(wù)的傳播行為為REQUIRES_NEW。根據(jù)具體情況選擇不同的事務(wù)傳播行為以確保應(yīng)用程序的數(shù)據(jù)一致性和可靠性。

spring事務(wù)默認(rèn)傳播行為

Spring的事務(wù)傳播行為默認(rèn)是PROPAGATION_REQUIRED,也就是如果當(dāng)前存在一個(gè)事務(wù),就加入該事務(wù);如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。

mysql事務(wù)默認(rèn)隔離級(jí)別

MySQL的事務(wù)隔離級(jí)別默認(rèn)是可重復(fù)讀(REPEATABLE READ),這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認(rèn)設(shè)置。這個(gè)隔離級(jí)別可以避免臟讀和不可重復(fù)讀的問題,但可能會(huì)出現(xiàn)幻讀的問題。

多線程事務(wù)控制

Spring實(shí)現(xiàn)事務(wù)通過ThreadLocal把事務(wù)和當(dāng)前線程進(jìn)行了綁定。

ThreadLocal作為本地線程變量載體,保存了當(dāng)前線程的變量,并確保所有變量是線程安全的。

這些封閉隔離的變量中就包含了數(shù)據(jù)庫連接,Session管理的對(duì)象以及當(dāng)前事務(wù)運(yùn)行的其他必要信息,而開啟的新線程是獲取不到這些變量和對(duì)象的。

也就是說:主線程事務(wù)與子線程事務(wù)是相互獨(dú)立的

怎么驗(yàn)證?

驗(yàn)證事務(wù) 以及 多線程事務(wù)控制編碼

package cn.cjf.tt;
import cn.cjf.tt.dao.UserMapper;
import cn.cjf.tt.po.User;
import cn.cjf.tt.service.UserService;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
// 使用Spring整合Junit專用的類加載器
@RunWith(SpringJUnit4ClassRunner.class)
// 加載配置文件或者配置類
@ContextConfiguration(locations = {"classpath:spring.xml"})//加載配置文件
public class UserTest {
    @Autowired
    private UserService userService;
    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private UserMapper userMapper;
    /**
     * 驗(yàn)證數(shù)據(jù)庫連接是否正常
     */
    @Test
    public void selectAllUser() {
        List<User> users = userService.selectAllUser();
        for (User i : users) {
            System.out.println(i);
        }
    }
    /**
     * 驗(yàn)證:能否正常插入數(shù)據(jù)
     */
    public void test() {
        final User user = new User() {{
            this.setUsername("test_" + UUID.randomUUID().toString());
            this.setPassword("123456");
            this.setCreateTime(new Date());
        }};
        userService.addUser(user);
    }
    /**
     * 驗(yàn)證:線程池子線程中能否正常插入數(shù)據(jù)
     */
    @Test
    public void testForBatch() throws InterruptedException {
        final ExecutorService service = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            service.submit(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    test1();
                }
            });
        }
        Thread.sleep(5000);
    }
    /**
     * 驗(yàn)證:正常插入數(shù)據(jù),拋出異常后,注解事務(wù)是否回滾
     */
    @Transactional(rollbackFor = Exception.class)
    @Test
    public void test1() throws Exception {
        final User user = new User() {{
            this.setUsername("test_" + UUID.randomUUID().toString());
            this.setPassword("123456");
            this.setCreateTime(new Date());
        }};
        userService.addUser(user);
        if (true) {
            throw new Exception();
        }
    }
    /**
     * 驗(yàn)證:正常插入數(shù)據(jù),拋出異常后,手動(dòng)事務(wù)是否回滾
     */
    @Test
    public void test11() {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            System.out.println(user);
            if (true) {
                throw new Exception();
            }
            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
            transactionManager.commit(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)回滾");
        }
    }
    /**
     * 驗(yàn)證:主線程事務(wù),是否能影響到子線程事務(wù)
     */
    @Transactional(rollbackFor = Exception.class)
    @Test
    public void test2() throws Exception {
        final User user = new User() {{
            this.setUsername("test_" + UUID.randomUUID().toString());
            this.setPassword("123456");
            this.setCreateTime(new Date());
        }};
        userService.addUser(user);
        System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
        final ExecutorService service = Executors.newFixedThreadPool(5);
        List<Integer> idList = new ArrayList<>();
        idList.add(user.getId());
        for (int i = 0; i < 5; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    final User user = new User() {{
                        this.setUsername("test_" + UUID.randomUUID().toString());
                        this.setPassword("123456");
                        this.setCreateTime(new Date());
                    }};
                    userService.addUserForTransaction(user);
                    System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
                    final Integer id = user.getId();
                    idList.add(id);
                }
            });
        }
        Thread.sleep(5000);
        try {
            throw new Exception();
        } finally {
            for (int i = 0; i < idList.size(); i++) {
                final Integer id = idList.get(i);
                final User po = userMapper.selectByPrimaryKey(id);
                if (po == null) {
                    System.out.println("---------------------id:" + id + "事務(wù)回滾");
                } else {
                    System.out.println("---------------------id:" + id + "事務(wù)提交");
                }
                // 主線程事務(wù)未結(jié)束
                // 實(shí)際主線程事務(wù)回滾了,但子線程事務(wù)未回滾
            }
        }
    }
    /**
     * 驗(yàn)證:主線程事務(wù),未能影響到子線程事務(wù),是因?yàn)樽泳€程的事務(wù)傳播行為影響
     */
    @Transactional(rollbackFor = Exception.class)
    @Test
    public void test21() throws Exception {
        final User user = new User() {{
            this.setUsername("test_" + UUID.randomUUID().toString());
            this.setPassword("123456");
            this.setCreateTime(new Date());
        }};
        userService.addUser(user);
        System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
        final ExecutorService service = Executors.newFixedThreadPool(5);
        List<Integer> idList = new ArrayList<>();
        idList.add(user.getId());
        for (int i = 0; i < 5; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    final User user = new User() {{
                        this.setUsername("test_" + UUID.randomUUID().toString());
                        this.setPassword("123456");
                        this.setCreateTime(new Date());
                    }};
                    userService.addUserForNestedTransaction(user);
                    System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
                    final Integer id = user.getId();
                    idList.add(id);
                }
            });
        }
        Thread.sleep(5000);
        try {
            throw new Exception();
        } finally {
            for (int i = 0; i < idList.size(); i++) {
                final Integer id = idList.get(i);
                final User po = userMapper.selectByPrimaryKey(id);
                if (po == null) {
                    System.out.println("---------------------id:" + id + "事務(wù)回滾");
                } else {
                    System.out.println("---------------------id:" + id + "事務(wù)提交");
                }
                // 主線程事務(wù)未結(jié)束
                // 實(shí)際主線程事務(wù)回滾了,但子線程事務(wù)未回滾
            }
        }
    }
    /**
     * 驗(yàn)證:主線程事務(wù),未能影響到子線程事務(wù)
     * 主線程手動(dòng)控制事務(wù),與注解自動(dòng)控制事務(wù),結(jié)果是否依然是,主線程事務(wù)不能影響到子線程事務(wù)
     */
    @Test
    public void test22() throws Exception {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        List<Integer> idList = new ArrayList<>();
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
            final ExecutorService service = Executors.newFixedThreadPool(5);
            idList.add(user.getId());
            for (int i = 0; i < 5; i++) {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        final User user = new User() {{
                            this.setUsername("test_" + UUID.randomUUID().toString());
                            this.setPassword("123456");
                            this.setCreateTime(new Date());
                        }};
                        userService.addUserForNestedTransaction(user);
                        System.out.println("---------------------" + Thread.currentThread().getName() + ":" + user);
                        final Integer id = user.getId();
                        idList.add(id);
                    }
                });
            }
            Thread.sleep(5000);
            if (true) {
                throw new Exception();
            }
            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)回滾");
        }
        for (int i = 0; i < idList.size(); i++) {
            final Integer id = idList.get(i);
            final User po = userMapper.selectByPrimaryKey(id);
            if (po == null) {
                System.out.println("---------------------id:" + id + "事務(wù)回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務(wù)提交");
            }
            // 主線程事務(wù)已結(jié)束
            // 主線程事務(wù)回滾了,但子線程事務(wù)未回滾
        }
    }
    /**
     * 驗(yàn)證:主線程事務(wù),未能影響到子線程事務(wù)
     * 主線程手動(dòng)控制事務(wù),子線程也手動(dòng)控制事務(wù),結(jié)果是否依然是,主線程事務(wù)不能影響到子線程事務(wù)
     */
    @Test
    public void test23() throws InterruptedException {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        List<Integer> idList = new ArrayList<>();
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            idList.add(user.getId());
            final ExecutorService service = Executors.newFixedThreadPool(5);
            for (int i = 0; i < 5; i++) {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
                        final TransactionStatus transaction = transactionManager.getTransaction(dd);
                        try {
                            final User user = new User() {{
                                this.setUsername("test_" + UUID.randomUUID().toString());
                                this.setPassword("123456");
                                this.setCreateTime(new Date());
                            }};
                            userService.addUser(user);
                            System.out.println(user);
                            final Integer id = user.getId();
                            idList.add(id);
                            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
                            transactionManager.commit(transaction);
                            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)提交");
                        } catch (Exception e) {
                            e.printStackTrace();
                            transactionManager.rollback(transaction);
                            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)回滾");
                        }
                    }
                });
            }
            Thread.sleep(5000);
            if (true) {
                throw new Exception();
            }
            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務(wù)回滾");
        }
        for (int i = 0; i < idList.size(); i++) {
            final Integer id = idList.get(i);
            final User po = userMapper.selectByPrimaryKey(id);
            if (po == null) {
                System.out.println("---------------------id:" + id + "事務(wù)回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務(wù)提交");
            }
            // 主線程事務(wù)已結(jié)束
            // 主線程事務(wù)回滾了,但子線程事務(wù)未回滾
        }
    }
    /**
     * 驗(yàn)證結(jié)果:主線程事務(wù)不能影響到子線程事務(wù)
     * <p>
     * 主線程,子線程控制各自事務(wù),等待一起提交
     */
    @Test
    public void test3() throws InterruptedException {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        List<Integer> idList = new ArrayList<>();
        int time = 5;
        CountDownLatch cdl = new CountDownLatch(time);
        AtomicBoolean flag = new AtomicBoolean(true);
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            idList.add(user.getId());
            final ExecutorService service = Executors.newFixedThreadPool(time);
            for (int i = 0; i < time; i++) {
                service.submit(new Runnable() {
                    @SneakyThrows
                    @Override
                    public void run() {
                        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
                        final TransactionStatus transaction = transactionManager.getTransaction(dd);
                        try {
                            final User user = new User() {{
                                this.setUsername("test_" + UUID.randomUUID().toString());
                                this.setPassword("123456");
                                this.setCreateTime(new Date());
                            }};
                            userMapper.insertSelective(user);
                            idList.add(user.getId());
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行成功");
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                                transactionManager.rollback(transaction);
                            }
                            System.out.println("---------------" + Thread.currentThread().getName() + "--End");
                        }
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                transactionManager.rollback(transaction);
            }
        }
        System.out.println("---------------" + Thread.currentThread().getName() + "--End");
        for (int i = 0; i < idList.size(); i++) {
            final Integer id = idList.get(i);
            final User po = userMapper.selectByPrimaryKey(id);
            if (po == null) {
                System.out.println("---------------------id:" + id + "事務(wù)回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務(wù)提交");
            }
            // 主線程事務(wù)已結(jié)束
            // 主線程事務(wù)回滾了,子線程事務(wù)也回滾
        }
    }
    /**
     * 驗(yàn)證結(jié)果:主線程事務(wù)不能影響到子線程事務(wù)
     * <p>
     * 主線程,子線程控制各自事務(wù),等待一起提交
     * 驗(yàn)證,主線程異常,子線程未異常,事務(wù)都回滾了
     */
    @Test
    public void test31() throws InterruptedException {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        List<Integer> idList = new ArrayList<>();
        int time = 5;
        CountDownLatch cdl = new CountDownLatch(time);
        AtomicBoolean flag = new AtomicBoolean(true);
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            idList.add(user.getId());
            final ExecutorService service = Executors.newFixedThreadPool(time);
            for (int i = 0; i < time; i++) {
//                int finalI = i;
                service.submit(new Runnable() {
                    @SneakyThrows
                    @Override
                    public void run() {
                        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
                        final TransactionStatus transaction = transactionManager.getTransaction(dd);
                        try {
                            final User user = new User() {{
                                this.setUsername("test_" + UUID.randomUUID().toString());
                                this.setPassword("123456");
                                this.setCreateTime(new Date());
                            }};
                            userMapper.insertSelective(user);
                            idList.add(user.getId());
                            // 最后一個(gè)提交的任務(wù),拋出異常;注釋掉會(huì)全部完成,否則全部回滾
//                            if (finalI == time - 1) {
//                                throw new RuntimeException();
//                            }
                            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行成功");
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                                transactionManager.rollback(transaction);
                            }
                            System.out.println("---------------" + Thread.currentThread().getName() + "--End");
                        }
                    }
                });
            }
            if (true) {
                throw new Exception();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                transactionManager.rollback(transaction);
            }
        }
        System.out.println("---------------" + Thread.currentThread().getName() + "--End");
        for (int i = 0; i < idList.size(); i++) {
            final Integer id = idList.get(i);
            final User po = userMapper.selectByPrimaryKey(id);
            if (po == null) {
                System.out.println("---------------------id:" + id + "事務(wù)回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務(wù)提交");
            }
            // 主線程事務(wù)已結(jié)束
            // 主線程事務(wù)回滾了,子線程事務(wù)也回滾
        }
    }
    /**
     * 驗(yàn)證結(jié)果:主線程事務(wù)不能影響到子線程事務(wù)
     * <p>
     * 主線程,子線程控制各自事務(wù),等待一起提交
     * 驗(yàn)證,主線程未異常,子線程異常,事務(wù)都回滾了
     */
    @Test
    public void test32() throws InterruptedException {
        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
        final TransactionStatus transaction = transactionManager.getTransaction(dd);
        List<Integer> idList = new ArrayList<>();
        int time = 5;
        CountDownLatch cdl = new CountDownLatch(time);
        AtomicBoolean flag = new AtomicBoolean(true);
        try {
            final User user = new User() {{
                this.setUsername("test_" + UUID.randomUUID().toString());
                this.setPassword("123456");
                this.setCreateTime(new Date());
            }};
            userService.addUser(user);
            idList.add(user.getId());
            final ExecutorService service = Executors.newFixedThreadPool(time);
            for (int i = 0; i < time; i++) {
                int finalI = i;
                service.submit(new Runnable() {
                    @SneakyThrows
                    @Override
                    public void run() {
                        DefaultTransactionDefinition dd = new DefaultTransactionDefinition();
                        final TransactionStatus transaction = transactionManager.getTransaction(dd);
                        try {
                            final User user = new User() {{
                                this.setUsername("test_" + UUID.randomUUID().toString());
                                this.setPassword("123456");
                                this.setCreateTime(new Date());
                            }};
                            userMapper.insertSelective(user);
                            idList.add(user.getId());
                            // 最后一個(gè)提交的任務(wù),拋出異常;注釋掉會(huì)全部完成,否則全部回滾
                            if (finalI == time - 1) {
                                throw new RuntimeException();
                            }
                            // User(id=13, username=test1694675733277, password=123456, salt=null, token=null, isEnabled=null, createTime=Thu Sep 14 15:15:33 CST 2023, modifiedTime=null)
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行成功");
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                                transactionManager.rollback(transaction);
                            }
                            System.out.println("---------------" + Thread.currentThread().getName() + "--End");
                        }
                    }
                });
            }
//            if (true) {
//                throw new Exception();
//            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務(wù)回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務(wù)");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務(wù)");
                transactionManager.rollback(transaction);
            }
        }
        System.out.println("---------------" + Thread.currentThread().getName() + "--End");
        for (int i = 0; i < idList.size(); i++) {
            final Integer id = idList.get(i);
            final User po = userMapper.selectByPrimaryKey(id);
            if (po == null) {
                System.out.println("---------------------id:" + id + "事務(wù)回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務(wù)提交");
            }
            // 主線程事務(wù)已結(jié)束
            // 主線程事務(wù)回滾了,子線程事務(wù)也回滾
        }
    }
}

到此這篇關(guān)于Spring 多線程事務(wù)控制的實(shí)踐的文章就介紹到這了,更多相關(guān)Spring 多線程事務(wù)控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 將Java程序的輸出結(jié)果寫入文件方法實(shí)例

    將Java程序的輸出結(jié)果寫入文件方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于將Java程序的輸出結(jié)果寫入文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Java使用正則表達(dá)式截取重復(fù)出現(xiàn)的XML字符串功能示例

    Java使用正則表達(dá)式截取重復(fù)出現(xiàn)的XML字符串功能示例

    這篇文章主要介紹了Java使用正則表達(dá)式截取重復(fù)出現(xiàn)的XML字符串功能,涉及java針對(duì)xml字符串及指定格式字符串的正則匹配相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Java中HashMap和Hashtable的區(qū)別小結(jié)

    Java中HashMap和Hashtable的區(qū)別小結(jié)

    本文主要介紹了Java中HashMap和Hashtable的區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 解決lambda表達(dá)式內(nèi)出現(xiàn)異常無法throw拋出的問題

    解決lambda表達(dá)式內(nèi)出現(xiàn)異常無法throw拋出的問題

    這篇文章主要介紹了lambda表達(dá)式內(nèi)出現(xiàn)異常無法throw拋出的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java使用google身份驗(yàn)證器實(shí)現(xiàn)動(dòng)態(tài)口令驗(yàn)證的示例

    java使用google身份驗(yàn)證器實(shí)現(xiàn)動(dòng)態(tài)口令驗(yàn)證的示例

    本篇文章主要介紹了java使用google身份驗(yàn)證器實(shí)現(xiàn)動(dòng)態(tài)口令驗(yàn)證的示例,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)

    java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)

    為避免繁瑣的注冊(cè)登陸,很多平臺(tái)和網(wǎng)站都會(huì)實(shí)現(xiàn)三方登陸的功能,增強(qiáng)用戶的粘性。這篇文章主要介紹了java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼),避免做微信登錄開發(fā)的朋友們少走彎路
    2022-12-12
  • 最新評(píng)論