Spring事務管理

来源:http://www.cnblogs.com/AndroidJotting/archive/2017/09/13/7517601.html
-Advertisement-
Play Games

對於Spring相信很多做web開發的小活動一定不陌生,Spring中我們經常談到的就是IOC和AOP,但是對於Spring的事務管理,相信大家一定也很感興趣,今天我們就探討一下Spring中的事務管理。 首先談一下事務使用的場景,我們能想到的最常見場景就是銀行轉賬,A給B轉賬,第一步扣除A中的賬戶 ...


  對於Spring相信很多做web開發的小活動一定不陌生,Spring中我們經常談到的就是IOC和AOP,但是對於Spring的事務管理,相信大家一定也很感興趣,今天我們就探討一下Spring中的事務管理。

  首先談一下事務使用的場景,我們能想到的最常見場景就是銀行轉賬,A給B轉賬,第一步扣除A中的賬戶金額,第二步將扣除的金額加入到B賬戶,這個過程就要求,這兩步,必須同時成功,如果失敗就需要進行事務回滾,不然我們的數據就會出現異常。這個怎麼來進行實現呢?這就要從今天的事務說起了。首先談一下事務的4大特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。

⑴ 原子性(Atomicity)

  原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,這和前面兩篇博客介紹事務的功能是一樣的概念,因此事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。

⑵ 一致性(Consistency)

  一致性是指事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。

  拿轉賬來說,假設用戶A和用戶B兩者的錢加起來一共是5000,那麼不管A和B之間如何轉賬,轉幾次賬,事務結束後兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。

⑶ 隔離性(Isolation)

  隔離性是當多個用戶併發訪問資料庫時,比如操作同一張表時,資料庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個併發事務之間要相互隔離。

  即要達到這麼一種效果:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始之前就已經結束,要麼在T1結束之後才開始,這樣每個事務都感覺不到有其他事務在併發地執行。

  關於事務的隔離性資料庫提供了多種隔離級別,稍後會介紹到。

⑷ 持久性(Durability)

  持久性是指一個事務一旦被提交了,那麼對資料庫中的數據的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作。

  例如我們在使用JDBC操作資料庫時,在提交事務方法後,提示用戶事務操作完成,當我們程式執行完成直到看到提示後,就可以認定事務以及正確提交,即使這時候資料庫出現了問題,也必須要將我們的事務完全執行完成,否則就會造成我們看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。

  以上介紹完事務的四大特性(簡稱ACID),現在重點來說明下事務的隔離性,當多個線程都開啟事務操作資料庫中的數據時,資料庫系統要能進行隔離操作,以保證各個線程獲取數據的準確性,在介紹資料庫提供的各種隔離級別之前,我們先看看如果不考慮事務的隔離性,會發生的幾種問題:1、臟讀:臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。2、不可重覆讀:不可重覆讀是指在對於資料庫中的某個數據,一個事務範圍內多次查詢卻返回了不同的數據值,這是由於在查詢間隔,被另一個事務修改並提交了。3、虛讀(幻讀):幻讀是事務非獨立執行時發生的一種現象。幻讀和不可重覆讀都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重覆讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。

  說了這麼多,下麵我們我們開始通過程式來簡單實現一下轉賬場景中如何使用事務。

  首先我們這裡需要搭建一個Spring下的轉賬場景,我使用的是jdk8+maven+spring+jdbc來模擬轉賬場景:

  1、打開eclipse(最新版本的直接支持maven環境),創建我們的maven項目

  2、打開pom.xml添加我們的jar依賴:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.edu.hpugs.spring</groupId>
  <artifactId>springTransation</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>springTransation</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
      <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.6</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.springframework/spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.3.11.RELEASE</version>
        <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.9.0</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

  這裡我們使用的是mysql資料庫,所以添加mysql驅動jar包;這裡我們使用spring-jdbc連接數據,所以引入spring-jdbc包;其次就是我們的spring相關jar包了

  3、編寫我們的service、dao層:

    a、service介面:

public interface IBlankService {
    
    void transferAccounts(final String outName, final String inName, final double monery);

}

    b、service實現:

public class BlankServiceImpl implements IBlankService {
    
    private IBlankDao blankDao;
    
    public void setBlankDao(IBlankDao blankDao) {
        this.blankDao = blankDao;
    }

    public void transferAccounts(String outName, String inName, double monery) {
        // TODO Auto-generated method stub
        blankDao.outMonery(outName, monery);
        int i = 1 / 0;
        blankDao.inMonery(inName, monery);
    }

}

    c、dao介面:

public interface IBlankDao {

    void outMonery(final String userName, final double monery);
    
    void inMonery(final String userName, final double monery);
    
}

    d、dao實現:

public class BlankDaoImpl implements IBlankDao {
    
    private DataSource dataSource;
    
    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void outMonery(String userName, double monery) {
        // TODO Auto-generated method stub
        String sql = "UPDATE userAccount SET monery = monery - ? WHERE name = ?";
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.update(sql, monery, userName);
    }

    public void inMonery(String userName, double monery) {
        // TODO Auto-generated method stub
        String sql = "UPDATE userAccount SET monery = monery + ? WHERE name = ?";
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.update(sql, monery, userName);
    }

}

  4、這裡我們通過junit單元測試的方法來調用我們的service:

public class UserTest {
    
    private IBlankService blankService;
    
    @Before
    public void before(){
        ApplicationContext appletContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        blankService = (IBlankService) appletContext.getBean("blankService");
    }
    
    @Test
    public void userTest(){
        blankService.transferAccounts("aa", "bb", 100);
    }

}

  5、我們的resource文件:

    a、applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    
    <context:property-placeholder location="classpath:db.properties"/>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.dirverClass}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    
    <bean id="blankService" class="com.edu.hpugs.spring.BlankServiceImpl">
        <property name="blankDao" ref="blankDao"></property>
    </bean>
    
    <bean id="blankDao" class="com.edu.hpugs.spring.BlankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
</beans>

    b、db.properties

jdbc.dirverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://127.0.0.1\:3306/blank?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
jdbc.user=root
jdbc.password=root

    c、log4j.properties

#log4j.rootCategory=error,stdout
#
#log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#log4j.appender.stdout.layout.ConversionPattern=[HYYT] %p [%t] %C.%M(%L) | %m%n
#
#log4j.logger.com.opensymphony.xwork2.ognl.OgnlValueStack=ERROR

##########################\u914d\u7f6erootLogger--\u8f93\u51fa\u6d88\u606f\u7ea7\u522b\uff1aINFO, WARN, ERROR\u548c FATAL ###############
#log4j.rootLogger = ALL, STUDIO, INFO_FILE, WARN_FILE, ERROR_FILE, FATAL_FILE
#####################################\u63a7\u5236\u53f0\u8f93\u51fa##################################################
log4j.rootLogger = ALL, INFO_FILE, WARN_FILE, ERROR_FILE
###############################################################################################
log4j.appender.STUDIO = org.apache.log4j.ConsoleAppender
log4j.appender.STUDIO.Targer = System.out
log4j.appender.STUDIO.Threshold = INFO
log4j.appender.STUDIO.ImmediateFlush = TRUE
log4j.appender.STUDIO.layout = org.apache.log4j.PatternLayout
log4j.appender.STUDIO.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH\:mm\:ss}][%l]%n%m%n
####################################INFO_FILE\u8f93\u51fa################################################
log4j.appender.INFO_FILE = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.INFO_FILE.Targer = /WebLogs/Info_File
log4j.appender.INFO_FILE.File = /WebLogs/springTransation/Info_File/log.txt
log4j.appender.INFO_FILE.Threshold = INFO
log4j.appender.INFO_FILE.ImmediateFlush = TRUE
log4j.appender.INFO_FILE.Append = TRUE
log4j.appender.INFO_FILE.Encoding = UTF-8
log4j.appender.WARN_FILE.DataPattern = '.'YYYY-MM-dd
log4j.appender.INFO_FILE.layout =  org.apache.log4j.PatternLayout
log4j.appender.INFO_FILE.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ss}][%l]%n%m%n
##################################WARN_FILE\u8f93\u51fa#################################################
log4j.appender.WARN_FILE = org.apache.log4j.DailyRollingFileAppender
log4j.appender.WARN_FILE.Targer = /WebLogs/Warn_File
log4j.appender.WARN_FILE.File = /WebLogs/springTransation/Warn_File/log.txt
log4j.appender.WARN_FILE.Threshold = WARN
log4j.appender.WARN_FILE.ImmediateFlush = TRUE
log4j.appender.WARN_FILE.Append = TRUE
log4j.appender.WARN_FILE.Encoding = UTF-8
log4j.appender.WARN_FILE.DataPattern = '.'YYYY-MM-dd
log4j.appender.WARN_FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.WARN_FILE.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ss}][%l]%n%m%n
##################################ERROR_FILE\u8f93\u51fa#################################################
log4j.appender.ERROR_FILE = org.apache.log4j.DailyRollingFileAppender
log4j.appender.ERROR_FILE.Targer = /WebLogs/Error_File
log4j.appender.ERROR_FILE.File = /WebLogs/springTransation/Error_File/log.txt
log4j.appender.ERROR_FILE.Threshold = ERROR
log4j.appender.ERROR_FILE.ImmediateFlush = TRUE
log4j.appender.ERROR_FILE.Append = TRUE
log4j.appender.ERROR_FILE.Encoding = UTF-8
log4j.appender.ERROR_FILE.DataPattern = '.'YYYY-MM-dd
log4j.appender.ERROR_FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.ERROR_FILE.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ss}][%l]%n%m%n
##################################FATAL_FILE\u8f93\u51fa################################################
log4j.appender.FATAL_FILE = org.apache.log4j.DailyRollingFileAppender
log4j.appender.FATAL_FILE.Targer = /WebLogs/Fatal_File
log4j.appender.FATAL_FILE.File = /WebLogs/springTransation/Fatal_File/log.txt
log4j.appender.FATAL_FILE.Threshold = FATAL
log4j.appender.FATAL_FILE.ImmediateFlush = TRUE
log4j.appender.FATAL_FILE.Append = TRUE
log4j.appender.FATAL_FILE.Encoding = UTF-8
log4j.appender.FATAL_FILE.DataPattern = '.'YYYY-MM-dd
log4j.appender.FATAL_FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.FATAL_FILE.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ss}][%l]%n%m%n

  到這裡我們的轉賬場景搭建就算完成了,下麵我們就簡單看一下如何進行事務管理:

  Spring中的事務管理分為:1、編程是事務;2、聲明式事務、3、基於註解的事務。

  Spring的事務有分為:

    傳播行為:

      PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。 

      PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。 

      PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。 

      PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。 

      PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 

      PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。 

    隔離級別:

      Serializable:最嚴格的級別,事務串列執行,資源消耗最大;   

      REPEATABLE READ:保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“臟讀取”和“不可重覆讀取”的情況,但是帶來了更多的性能損失。

      READ COMMITTED:大多數主流資料庫的預設事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“臟讀取”。該級別適用於大多數系統。

      Read Uncommitted:保證了讀取過程中不會讀取到非法數據。隔離級別在於處理多事務的併發問題。 

   下麵我們先一起探討一下關於編程式的事務管理,首先我們要明白事務應該載入那一層,我們知道Dao是我們的持久層,service是我們的業務層,而我們的事務應當加在業務層,而非持久層。

  1、通過TransactionManager來進行我們的事務管理,修改applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    
    <context:property-placeholder location="classpath:db.properties"/>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.dirverClass}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    
    <bean id="blankDao" class="com.edu.hpugs.spring.BlankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <bean id="blankService" class="com.edu.hpugs.spring.BlankServiceImpl">
        <property name="blankDao" ref="blankDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>
    
</beans>

  2、同樣修改serviceImpl.java

public class BlankServiceImpl implements IBlankService {
    
    private IBlankDao blankDao;
    
    public void setBlankDao(IBlankDao blankDao) {
        this.blankDao = blankDao;
    }
    
    private TransactionTemplate transactionTemplate;
    
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transferAccounts(final String outName, final String inName, final double monery) {
        // TODO Auto-generated method stub
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                // TODO Auto-generated method stub
                blankDao.outMonery(outName, monery);
                int i = 1 / 0;
                blankDao.inMonery(inName, monery);
            }
        });
    }

}

  到這裡Spring編程式的註解就完成了。源碼下載

  下麵我們看一下基於聲明式的事務管理:

  1、對於聲明式的事務管理,Spring是基於AOP來實現的,所以我們需要在maven中添加aop相關的依賴

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.10</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.10</version>
    </dependency>

  2、將我們的場景代碼恢復如初,然後修改我們的applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    
    <context:property-placeholder location="classpath:db.properties"/>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.dirverClass}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    
    <bean id="blankDao" class="com.edu.hpugs.spring.BlankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <bean id="blankService" class="com.edu.hpugs.spring.BlankServiceImpl">
        <property name="blankDao" ref="blankDao"></property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--配置事務增強(如何管理事務,只讀、讀寫...)-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="out*" propagation="REQUIRED" />
            <tx:method name="in*" propagation="REQUIRED" />
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
    
    <!--aop配置,攔截哪些方法(切入點表達式,攔截上面的事務增強)-->
    <aop:config>
        <aop:pointcut id="pt" expression="execution(* com.edu.hpugs.spring.BlankServiceImpl.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>
    
</beans>

  好了,到這裡關於Spring中的聲明式事務就介紹完畢。源碼下載

  最後時我們基於註解的事務管理

  1、基於註解的事務管理,需要我們通過maven添加註解依賴:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>

  2、修改applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡單的BBS論壇 實現功能 git倉庫地址: https://github.com/uge3/BBS 1、整體參考“抽屜新熱榜” + “博客園” 2、實現不同論壇版塊 3、帖子列表展示 4、個人博客主頁 5、個人博客標簽、分類、時間 篩選 6、帖子評論數、點贊數展示 7、允許登錄用戶發貼、評論、點贊 ...
  • redis筆記 下載完redis,執行make命令。 然後啟動redis就進src文件夾,執行./redis-server就可以了。 再在文件夾下執行 ./redis-cli 就可以執行redis的命令了。 pipelining 一次請求發送多個命令,以提高性能。我們在使用redis時都是向它發送命 ...
  • 拼接: name=zhuhuan age=23 salary=333 info=''' info of %s age:%s name:%s salary:%s %(name,age,name,salary) ''' info2=''' info of {_name} age:{_age} name: ...
  • JPA基礎及查詢規則 JPA JPA是Java Persistence API的簡稱,中文名Java持久層API,是JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到資料庫中。 JPA框架中支持大數據集、事務、併發等容器級事務,這使得 JPA 超越了簡單持久化框架的局 ...
  • 1.減少可調用對象的參數個數,使用functools.partial凍結參數 使用functools.partial(),可以固定一個或者多個值,減少調用參數。 2.給函數參數增加元信息 函數聲明中的各個參數可以在 : 之後增加註解表達式。如果參數有預設值,註解放在參數名和 = 號之間。如果想註解返 ...
  • package com.swift; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import ja... ...
  • 承接【Spring事務管理】,上一篇我們已經簡單接觸了關於Spring jdbc的知識,今天我們承接上一篇進行一下補充,上一篇直接將dataSource註入到了Dao層進行了實現,本篇我們通過簡單進行一下補充,將另外兩種實現為大家進行一下演示:1、在自己定義的DAO 實現類中註入一個DataSour ...
  • Coloring Trees CodeForces - 711C 題意:有n個點,每個點有一個c值,如果為0表示它沒有被染色,否則表示它被染成了c值的顏色。顏色有1到m。把第i棵樹染成顏色j所需要的代價是p[i][j]。求最小的代價,使得將每棵樹都染色,且如果將連續的一串同色的樹視為一個集合,共有k ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...