亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring 多線程事務控制的實踐

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

在Java多線程事務控制中,有一些注意事項和實例可以幫助你更好地理解和應用。

注意事項

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

spring事務隔離級別

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

以下是Spring框架支持的事務隔離級別及其詳細說明:

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

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

在Spring中,可以通過以下方式設置事務的隔離級別:

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

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

spring事務傳播行為

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

以下是Spring框架支持的事務傳播行為及其詳細說明:

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

在Spring中,可以通過以下方式設置事務的傳播行為:

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

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

spring事務默認傳播行為

Spring的事務傳播行為默認是PROPAGATION_REQUIRED,也就是如果當前存在一個事務,就加入該事務;如果當前沒有事務,就新建一個事務。

mysql事務默認隔離級別

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

多線程事務控制

Spring實現(xiàn)事務通過ThreadLocal把事務和當前線程進行了綁定。

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

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

也就是說:主線程事務與子線程事務是相互獨立的

怎么驗證?

驗證事務 以及 多線程事務控制編碼

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;
    /**
     * 驗證數(shù)據(jù)庫連接是否正常
     */
    @Test
    public void selectAllUser() {
        List<User> users = userService.selectAllUser();
        for (User i : users) {
            System.out.println(i);
        }
    }
    /**
     * 驗證:能否正常插入數(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);
    }
    /**
     * 驗證:線程池子線程中能否正常插入數(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);
    }
    /**
     * 驗證:正常插入數(shù)據(jù),拋出異常后,注解事務是否回滾
     */
    @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();
        }
    }
    /**
     * 驗證:正常插入數(shù)據(jù),拋出異常后,手動事務是否回滾
     */
    @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() + "事務提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務回滾");
        }
    }
    /**
     * 驗證:主線程事務,是否能影響到子線程事務
     */
    @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 + "事務回滾");
                } else {
                    System.out.println("---------------------id:" + id + "事務提交");
                }
                // 主線程事務未結(jié)束
                // 實際主線程事務回滾了,但子線程事務未回滾
            }
        }
    }
    /**
     * 驗證:主線程事務,未能影響到子線程事務,是因為子線程的事務傳播行為影響
     */
    @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 + "事務回滾");
                } else {
                    System.out.println("---------------------id:" + id + "事務提交");
                }
                // 主線程事務未結(jié)束
                // 實際主線程事務回滾了,但子線程事務未回滾
            }
        }
    }
    /**
     * 驗證:主線程事務,未能影響到子線程事務
     * 主線程手動控制事務,與注解自動控制事務,結(jié)果是否依然是,主線程事務不能影響到子線程事務
     */
    @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() + "事務提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務回滾");
        }
        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 + "事務回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務提交");
            }
            // 主線程事務已結(jié)束
            // 主線程事務回滾了,但子線程事務未回滾
        }
    }
    /**
     * 驗證:主線程事務,未能影響到子線程事務
     * 主線程手動控制事務,子線程也手動控制事務,結(jié)果是否依然是,主線程事務不能影響到子線程事務
     */
    @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() + "事務提交");
                        } catch (Exception e) {
                            e.printStackTrace();
                            transactionManager.rollback(transaction);
                            System.out.println("---------------------" + Thread.currentThread().getName() + "事務回滾");
                        }
                    }
                });
            }
            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() + "事務提交");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
            System.out.println("---------------------" + Thread.currentThread().getName() + "事務回滾");
        }
        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 + "事務回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務提交");
            }
            // 主線程事務已結(jié)束
            // 主線程事務回滾了,但子線程事務未回滾
        }
    }
    /**
     * 驗證結(jié)果:主線程事務不能影響到子線程事務
     * <p>
     * 主線程,子線程控制各自事務,等待一起提交
     */
    @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í)行失敗,等待事務回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                                transactionManager.rollback(transaction);
                            }
                            System.out.println("---------------" + Thread.currentThread().getName() + "--End");
                        }
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("---------------" + Thread.currentThread().getName() + "--執(zhí)行失敗,等待事務回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                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 + "事務回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務提交");
            }
            // 主線程事務已結(jié)束
            // 主線程事務回滾了,子線程事務也回滾
        }
    }
    /**
     * 驗證結(jié)果:主線程事務不能影響到子線程事務
     * <p>
     * 主線程,子線程控制各自事務,等待一起提交
     * 驗證,主線程異常,子線程未異常,事務都回滾了
     */
    @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());
                            // 最后一個提交的任務,拋出異常;注釋掉會全部完成,否則全部回滾
//                            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í)行失敗,等待事務回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                                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í)行失敗,等待事務回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                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 + "事務回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務提交");
            }
            // 主線程事務已結(jié)束
            // 主線程事務回滾了,子線程事務也回滾
        }
    }
    /**
     * 驗證結(jié)果:主線程事務不能影響到子線程事務
     * <p>
     * 主線程,子線程控制各自事務,等待一起提交
     * 驗證,主線程未異常,子線程異常,事務都回滾了
     */
    @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());
                            // 最后一個提交的任務,拋出異常;注釋掉會全部完成,否則全部回滾
                            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í)行失敗,等待事務回滾");
                            flag.set(false);
                        } finally {
                            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
                            cdl.countDown();
                            cdl.await();
                            if (flag.get()) {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                                transactionManager.commit(transaction);
                            } else {
                                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                                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í)行失敗,等待事務回滾");
            flag.set(false);
        } finally {
            System.out.println("---------------" + Thread.currentThread().getName() + "--等待");
            cdl.await();
            if (flag.get()) {
                System.out.println("---------------" + Thread.currentThread().getName() + "--提交事務");
                transactionManager.commit(transaction);
            } else {
                System.out.println("---------------" + Thread.currentThread().getName() + "--回滾事務");
                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 + "事務回滾");
            } else {
                System.out.println("---------------------id:" + id + "事務提交");
            }
            // 主線程事務已結(jié)束
            // 主線程事務回滾了,子線程事務也回滾
        }
    }
}

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

相關文章

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

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

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

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

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

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

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

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

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

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

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

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

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