Spring事務管理

Spring事務管理分爲聲明式事務管理編程式事務管理,聲明式事務管理又分爲xml註解兩種配置方式。應該優先選擇聲明式事務,由於聲明式事務對程序代碼的影響最小,所以最符合非侵入式輕量級容器的理想 。只有在進行少許事務操做時,才應該選擇編程式事務管理的方式。java

聲明式事務管理

xml配置方式

Spring配置文件:

<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 導入數據庫配置文件 -->
    <context:property-placeholder location="config.properties"/>
    
    <!-- 配置數據源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        init-method="init" destroy-method="close">
        <property name="driverClassName"><value>${jdbc_driverClassName}</value></property>
        <property name="url"><value>${jdbc_url}</value></property>
        <property name="username"><value>${jdbc_username}</value></property>
        <property name="password"><value>${jdbc_password}</value></property>
        <!-- ... -->
    </bean>
    
    <!-- 配置jdbcTemplate,使用jdbcTemplate操做數據庫 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean id="userService" class="com.springdemo.tx.UserService">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    
    <!-- 配置事務管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- xml方式的配置聲明式事務 start-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/>
    </aop:config>
    <!-- xml方式的配置聲明式事務 end-->
</beans>

config.properties:

jdbc_driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://192.168.1.77:3306/testdb?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
jdbc_username=root
jdbc_password=root

UserService.java:

public class UserService {
    private JdbcTemplate jdbcTemplate;

    public void addUser(String name, int age){
        jdbcTemplate.update("insert into test007 (name,age) values (name,age)", name, age);
    }
    
    public void updateUserName(String name, int id){
        jdbcTemplate.update("update test007 set name=? where id=?", name, id);
    }
    
    public void updateUserAge(int age, int id){
        jdbcTemplate.update("update test007 set age=? where id=?", age, id);
    }
    
    public void updateUser(String name, int age, int id){
        updateUserName(name, id);
        //模擬異常
        Double.parseDouble("我不是Double,因此會拋出NumberFormatException異常");
        updateUserAge(age, id);
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

main方法:

public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService = (UserService) ac.getBean("userService");
        userService.updateUser("小王", 18, 1);
}

使用註解方式

Spring配置文件中添加:

<!-- 開啓註解配置 -->
    <tx:annotation-driven transaction-manager="txManager"/>

而後在須要事務管理的方法上添加@Transactional註解mysql

@Transactional
    public void updateUser(String name, int age, int id){
        updateUserName(name, id);
        //模擬異常
        Double.parseDouble("我不是Double,因此會拋出NumberFormatException異常");
        updateUserAge(age, id);
    }

注意:註解方式和xml方式能夠二選一,也能夠結合使用,二者沒有依賴關係。spring

異常捕獲和回滾

異常捕獲會致使事務機制失效,繼而不會觸發回滾。
能夠調用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手動回滾。sql

@Transactional
    public void updateUser(String name, int age, int id){
        try{
            updateUserName(name, id);
            //模擬異常
            Double.parseDouble("我不是Double,因此會拋出NumberFormatException異常");
            updateUserAge(age, id);
        }catch(NumberFormatException ex){
            //手動回滾
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            ex.printStackTrace();
        }
    }

非RuntimeException時回滾

Spring事務管理機制默認只在拋出RuntimeException時纔會觸發回滾,能夠設置rollbackFor屬性來指定其餘類型的異常也能回滾。數據庫

//rollbackFor指定拋出Exception類型異常時回滾
    @Transactional(rollbackFor=Exception.class)
    public void updateUser(String name, int age, int id) throws Exception{
        updateUserName(name, id);
        if(id == 1){
            throw new Exception("Id爲1的用戶不可修改");
        }
        updateUserAge(age, id);
    }

編程式事務管理

修改Spring配置文件:

<bean id="userService" class="com.springdemo.tx.UserService">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
    
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 
        <property name="transactionManager" ref="txManager"/>
    </bean>
    
    <!-- 註釋聲明式事務管理配置 -->
    <!-- <tx:annotation-driven transaction-manager="txManager"/>
    
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/>
    </aop:config> -->

修改UserService:

private TransactionTemplate transactionTemplate;

    public void updateUser(final String name, final int age, final int id){
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                updateUserName(name, id);
                //模擬異常
                Double.parseDouble("我不是Double,因此會拋出NumberFormatException異常");
                updateUserAge(age, id);
            }
        });
    }

    public TransactionTemplate getTransactionTemplate() {
        return transactionTemplate;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
相關文章
相關標籤/搜索