1. 程式人生 > >Spring整合MyBatis 事務管理

Spring整合MyBatis 事務管理

前言

        spring事務管理包含兩種情況,程式設計式事務、宣告式事務。而宣告式事務又包括基於註解@Transactional和tx+aop的方式。那麼本文先分析程式設計式註解事務和基於註解的宣告式事務。 程式設計式事務管理使用TransactionTemplate或者PlatformTransactionManager。對於程式設計式事務spring推薦使用TransactionTemplate。

一、程式設計式事務

     spring事務特性

     spring中所有的事務策略類都繼承自org.springframework.transaction.PlatformTransactionManager介面

複製程式碼

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    
    void rollback(TransactionStatus status) throws TransactionException;

}

複製程式碼

      程式設計式事務TransactionTemplate需要手動在程式碼中處理事務,一般不推薦使用,也不符合spring的思想,因為它直接耦合程式碼,但各有利弊。先看下TransactionTemplate的原始碼。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

public class TransactionTemplate extends DefaultTransactionDefinition

implements TransactionOperations, InitializingBean {

protected final Log logger = LogFactory.getLog(getClass());

private PlatformTransactionManager transactionManager;

public TransactionTemplate() {

}

public TransactionTemplate(PlatformTransactionManager transactionManager) {

this.transactionManager = transactionManager;

}

public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) {

super(transactionDefinition);

this.transactionManager = transactionManager;

}

public void setTransactionManager(PlatformTransactionManager transactionManager) {

this.transactionManager = transactionManager;

}

public PlatformTransactionManager getTransactionManager() {

return this.transactionManager;

}

@Override

public void afterPropertiesSet() {

if (this.transactionManager == null) {

throw new IllegalArgumentException("Property 'transactionManager' is required");

}

}

@Override

public <T> T execute(TransactionCallback<T> action) throws TransactionException {

if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {

return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);

}

else {

TransactionStatus status = this.transactionManager.getTransaction(this);

T result;

try {

result = action.doInTransaction(status);

}

catch (RuntimeException ex) {

// Transactional code threw application exception -> rollback

rollbackOnException(status, ex);

throw ex;

}

catch (Error err) {

// Transactional code threw error -> rollback

rollbackOnException(status, err);

throw err;

}

catch (Throwable ex) {

// Transactional code threw unexpected exception -> rollback

rollbackOnException(status, ex);

throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");

}

this.transactionManager.commit(status);

return result;

}

}

private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {

logger.debug("Initiating transaction rollback on application exception", ex);

try {

this.transactionManager.rollback(status);

}

catch (TransactionSystemException ex2) {

logger.error("Application exception overridden by rollback exception", ex);

ex2.initApplicationException(ex);

throw ex2;

}

catch (RuntimeException ex2) {

logger.error("Application exception overridden by rollback exception", ex);

throw ex2;

}

catch (Error err) {

logger.error("Application exception overridden by rollback error", ex);

throw err;

}

}

}

  從上面的程式碼可以看到核心方法是execute,該方法入參TransactionCallback<T>。檢視TransactionCallback原始碼:

1

2

3

public interface TransactionCallback<T> {

T doInTransaction(TransactionStatus status);

}

 那麼以上兩個原始碼可以確定我們使用程式設計式事務管理的方式也就是自己需要重寫doInTransaction()。OK,那麼我們手動使用TransactionTemplate處理下。

1、先配置transactionmanager

 <!--事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

2、配置transactionTemplate

 <!--程式設計式事務,推薦使用TransactionTemplate-->
    <bean id="transactionTemplate"
          class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

3、業務程式碼處理

複製程式碼

 @Autowired
    private TransactionTemplate transactionTemplate;

    public int insertUser2(final User user) {
        Integer i= (Integer) this.transactionTemplate.execute(new TransactionCallback() {
            public Object doInTransaction(TransactionStatus transactionStatus) {

                int i = userMapper.insertUser(user);
                if (i > 0) {
                    System.out.println("success");
                }
                int j = 10 / 0;

                return i;

            }
        });

        return i;
    }

複製程式碼

  業務程式碼中我們使用by zero的異常故意丟擲,你會發現能繼續列印success,當你斷點debug時,你會發現資料庫一直是鎖定狀態,直到你程式執行完。如下圖:

二、基於Transactional註解的事務管理

    當前應該是使用最清爽的事務管理方式了,也符合spring的理念,非入侵程式碼的方式。

1、配置

複製程式碼

 <!--事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

 <!-- 使用註解事務,需要新增Transactional註解屬性 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

 <!--啟用最新的註解器、對映器-->
    <mvc:annotation-driven/>

複製程式碼

2、配置後只需要在要處理的地方加上Transactional註解,而且Transactional註解的方式可以應用在類上,也可以應用在方法上,當然只針對public方法。

3、業務程式碼處理

複製程式碼

  @Transactional
    public int insertUser(User user) {
        int i = userMapper.insertUser(user);
        if (i > 0) {
            System.out.println("success");
        }
        int j = 10 / 0;

        return i;
    }

複製程式碼

  參考資料