1. 程式人生 > >使用註解實現Spring的宣告式事務管理

使用註解實現Spring的宣告式事務管理

使用註解實現Spring的宣告式事務管理,更加簡單!

步驟:

         1) 必須引入Aop相關的jar檔案

         2) bean.xml中指定註解方式實現宣告式事務管理以及應用的事務管理器類

         3)在需要新增事務控制的地方,寫上: @Transactional

 

@Transactional註解:

         1)應用事務的註解

         2)定義到方法上: 當前方法應用spring的宣告式事務

         3)定義到類上:   當前類的所有的方法都應用Spring宣告式事務管理;

         4)定義到父類上: 當執行父類的方法時候應用事務。

事務傳播行為:

         Propagation.REQUIRED

                   指定當前的方法必須在事務的環境下執行;

                   如果當前執行的方法,已經存在事務, 就會加入當前的事務;

         Propagation.REQUIRED_NEW

                   指定當前的方法必須在事務的環境下執行;

                   如果當前執行的方法,已經存在事務:  事務會掛起; 會始終開啟一個新的事務,執行完後;  剛才掛起的事務才繼續執行。

舉例:
Class Log{
        Propagation.REQUIRED  
        insertLog();  
}

    Propagation.REQUIRED
    Void  saveDept(){
        insertLog();    // 加入當前事務
        .. 異常, 會回滾
        saveDept();
    }


    Class Log{
        Propagation.REQUIRED_NEW  
        insertLog();  
}

    Propagation.REQUIRED
    Void  saveDept(){
        insertLog();    // 始終開啟事務
        .. 異常, 日誌不會回滾
        saveDept();
    }
測試步驟:
    1)日誌表Log_
    2)LogService.java
            insertLog();

 


package loaderman.b_anno;

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

// 測試: 日誌傳播行為
@Repository
public class LogDao {

    @Resource
    private JdbcTemplate jdbcTemplate;

    // 始終開啟事務
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertLog() {
        jdbcTemplate.update("insert into log_ values('在儲存Dept..')");
    }
}
package loaderman.b_anno;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * Service

 */
@Service
public class DeptService {

    // 部門dao
    @Resource
    private DeptDao deptDao;

    // 日誌dao
    @Resource
    private LogDao logDao;

    /*
     * 事務控制?
     */
    @Transactional(
            readOnly = false,  // 讀寫事務
            timeout = -1,       // 事務的超時時間不限制
            //noRollbackFor = ArithmeticException.class,  // 遇到數學異常不回滾
            isolation = Isolation.DEFAULT,              // 事務的隔離級別,資料庫的預設
            propagation = Propagation.REQUIRED            // 事務的傳播行為
    )
    public void save(Dept dept){
        logDao.insertLog();  // 儲存日誌  【自己開啟一個事務】
        int i = 1/0;
        deptDao.save(dept);  // 儲存部門
    }
}
package loaderman.b_anno;

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * dao實現,使用Spring對jdbc支援功能
 */
@Repository
public class DeptDao {

    @Resource
    private JdbcTemplate jdbcTemplate;

    public void save(Dept dept){
        String sql = "insert into t_dept (deptName) values(?)";
        jdbcTemplate.update(sql,dept.getDeptName());
    }
}
package loaderman.b_anno;

public class Dept {

    private int deptId;
    private String deptName;
    public int getDeptId() {
        return deptId;
    }
    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    
}
package loaderman.b_anno;

import java.util.Arrays;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    @Test
    public void testApp() throws Exception {
        //容器物件
        ApplicationContext ac = new ClassPathXmlApplicationContext("loaderman/b_anno/bean.xml");

        // 模擬資料
        Dept dept = new Dept();
        dept.setDeptName("測試: 開發部");

        DeptService deptService = (DeptService) ac.getBean("deptService");
        deptService.save(dept);
    }

    // 瞭解容器的相關方法
    @Test
    public void testApp2() throws Exception {
        //1. 根據bean.xml配置路徑,建立容器物件
        //ApplicationContext ac = new ClassPathXmlApplicationContext("loaderman/b_anno/bean.xml");

        //2. 根據多個配置檔案的路徑,建立容器物件
        //ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{});

        //3.  容器物件相關方法
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("loaderman/b_anno/bean.xml");
        //3.1 從容器中獲取指定名稱的bean物件
        //DeptDao deptDao = (DeptDao) ac.getBean("deptDao");
        //3.2 根據型別從容器獲取例項 【改型別只能在IOC中有唯一的物件,否則報錯】
        //DeptDao deptDao = ac.getBean(DeptDao.class);
        //3.3 泛型,不需要強轉
        //DeptDao deptDao = ac.getBean("deptDap", DeptDao.class);
        //3.4 獲取容器中bean物件的數量
        //int count = ac.getBeanDefinitionCount();
        String[] names = ac.getBeanDefinitionNames();
        System.out.println(Arrays.toString(names));
    }
}
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">

    
    <!-- 1. 資料來源物件: C3P0連線池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="initialPoolSize" value="3"></property>
        <property name="maxPoolSize" value="10"></property>
        <property name="maxStatements" value="100"></property>
        <property name="acquireIncrement" value="2"></property>
    </bean>
    
    <!-- 2. JdbcTemplate工具類例項 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 事務管理器類 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 開啟註解掃描 -->
    <context:component-scan base-package="loaderman.b_anno"></context:component-scan>
    
    <!-- 註解方式實現事務: 指定註解方式實現事務 -->
    <tx:annotation-driven transaction-manager="txManager"/>
    
    <bean class="loaderman.b_anno.DeptDao"></bean>
</beans>