Spring事務管理實現方式(註解,Xml)

事務隔離級別和傳播行爲

Isolation :隔離級別java

隔離級別是指若干個併發的事務之間的隔離程度,與咱們開發時候主要相關的場景包括:髒讀取、重複讀、幻讀。mysql

具體的設置方式(註解):例如@Transactional(isolation = Isolation.DEFAULT )spring

隔離級別 含義
DEFAULT 使用數據庫默認的事務隔離級別
READ_UNCOMMITTED 容許讀取還沒有提交的修改,可能致使髒讀、幻讀和不可重複讀
READ_COMMITTED 容許從已經提交的事務讀取,可防止髒讀、但幻讀,不可重複讀仍然有可能發生
REPEATABLE_READ 對相同字段的屢次讀取的結果是一致的,除非數據被當前事務自生修改。可防止髒讀和不可重複讀,但幻讀仍有可能發生
SERIALIZABLE 徹底服從acid隔離原則,確保不發生髒讀、不可重複讀、和幻讀,但執行效率最低。

Propagation:傳播行爲sql

所謂事務的傳播行爲是指,若是在開始當前事務以前,一個事務上下文已經存在,此時有若干選項能夠指定一個事務性方法的執行行爲。數據庫

具體的設置方式(註解):@Transactional(propagation = Propagation.REQUIRED)express

傳播行爲 含義
REQUIRED 表示當前方法必須在一個具備事務的上下文中運行,若有客戶端有事務在進行,那麼被調用端將在該事務中運行,不然的話從新開啓一個事務。(若是被調用端發生異常,那麼調用端和被調用端事務都將回滾)
MANDATORY 表示當前方法必須在一個事務中運行,若是沒有事務,將拋出異常
NEVER 表示當方法務不該該在一個事務中運行,若是存在一個事務,則拋出異常
NOT_SUPPORTED 表示該方法不該該在一個事務中運行。若是有一個事務正在運行,他將在運行期被掛起,直到這個事務提交或者回滾才恢復執行
SUPPORTS 表示當前方法沒必要須要具備一個事務上下文,可是若是有一個事務的話,它也能夠在這個事務中運行
NESTED 表示若是當前方法正有一個事務在運行中,則該方法應該運行在一個嵌套事務中,被嵌套的事務能夠獨立於被封裝的事務中進行提交或者回滾。若是封裝事務存在,而且外層事務拋出異常回滾,那麼內層事務必須回滾,反之,內層事務並不影響外層事務。若是封裝事務不存在,則同propagation_required的同樣
REQUIRES_NEW 表示當前方法必須運行在它本身的事務中。一個新的事務將啓動,並且若是有一個現有的事務在運行的話,則這個方法將在運行期被掛起,直到新的事務提交或者回滾才恢復執行。

基於Aspectj AOP配置事務

幾點說明:編程

導入外部資源文件後端

<context:property-placeholder location="classpath:db.properties"></context:property-placeholder

註冊組件包掃描,把類上標註了@Controller @Service @Repository @Component 都會自動加入到Spring容器中springboot

<context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan>

<<tx:advice>>配置一個事物通知,即執行的方法隔離級別和傳播行爲, <<aop:config>>配置事務通知在類上執行操做(切入點)。併發

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 爲鏈接點指定事務屬性 -->
            <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
    </aop:config>

實現步驟:

​ 一、定義數據庫的配置文件(db.properties),定義業務類UserDao,UserService。

​ 二、定義Spring的配置文件(spring-aspect.xml)

​ 導入經過<<context:property-placeholder>>導入數據庫配置文件,而後經過包掃描的方式<<context:component-scan>>把UserDao,UserService註冊到Spring的容器當中,配置數據額源,JDBC 的模板,最後事務管理器,配置事務通知,切入點。

配置文件(db.properties)

db.username=root
db.password=root
db.url=jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
db.driverClass=com.mysql.jdbc.Driver

業務類(UserDao,UserService)

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insertUser() {
        String sql = "INSERT INTO t_user (username,`password`) VALUES(?,?);";
        String username = UUID.randomUUID().toString().substring(0, 3);
        jdbcTemplate.update(sql, username, 12);
        System.out.println("插入成功");
        int i=10/0;
    }

}

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void insertUser() {
        userDao.insertUser();
    }
}

Spring配置文件(spring-aspect.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: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">

    <!-- 導入外部資源文件 -->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!--包掃描,把類上標註了@Controller @Service @Repository @Component 都會自動加入到Spring容器中-->
    <context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan>
    <!-- 配置C3P0數據源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
        <property name="jdbcUrl" value="${db.url}"></property>
        <property name="driverClass" value="${db.driverClass}"></property>
    </bean>
    <!-- 配置Spring 的JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></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="insert*" isolation="DEFAULT" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
    </aop:config>
</beans>

測試方法

public class AspectTest {
    @Test
    public void aspectAop(){
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-aspect.xml");
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insertUser();
    }
}

基於 @Transactional 的聲明式事務管理

基於註解實現

第一步是在須要事務的類或者方法上面添加@Transactional() 註解,裏面能夠經過propagation和isolation指定事務的隔離級別和傳播行爲。

@Service
public class UserService {

    @Autowired
    private UserDao userDao;
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
    public void insertUser() {
        userDao.insertUser();
    }
}

@EnableTransactionManagement 來啓用註解式事務管理,至關於以前在xml中配置的<tx:annotation-driven />註解驅動。

經過包掃描@ComponentScan至關於 <<context:component-scan>>實現業務類註冊到Spring容器當中。

經過@PropertySource和 @Value實現讀取配置文件,而且把之賦值到對應的屬性當中。

@Configuration 說明該類是一個配置類至關於(<beans></beans>),@Bean 至關於(<bean></bean>),註冊數據源,JDBC模板,事務管理器。

@EnableTransactionManagement
@ComponentScan(basePackages = "zfcoding.tx")
@PropertySource("classpath:db.properties")
@Configuration
public class MyDataSourceConfig {

    @Value("${db.username}")
    private String username;
    @Value("${db.password}")
    private String password;
    @Value("${db.url}")
    private String url;
    @Value("${db.driverClass}")
    private String driveClass;

    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(username);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl(url);
        dataSource.setDriverClass(driveClass);
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }
    //註冊事務管理器在容器中
    @Bean
    public PlatformTransactionManager transactionManager() throws PropertyVetoException {
        return new DataSourceTransactionManager(dataSource());
    }
}

測試類

public class TxTest {
    @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyDataSourceConfig.class);
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insertUser();
    }
}

基於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: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">

    <!-- 導入外部資源文件 -->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!--包掃描,把類上標註了@Controller @Service @Repository @Component 都會自動加入到Spring容器中-->
    <context:component-scan base-package="zfcoding.xmltx"></context:component-scan>
    <!-- 配置C3P0數據源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
        <property name="jdbcUrl" value="${db.url}"></property>
        <property name="driverClass" value="${db.driverClass}"></property>
    </bean>
    <!-- 配置Spring 的JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--開啓自動事務掃描-->
    <!-- 啓用事務註解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

測試類

public class XmlTxTest {
    @Test
    public void test(){
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:bean.xml");
        UserServiceXml userServiceXml = applicationContext.getBean(UserServiceXml.class);
        userServiceXml.insertUser();
    }
}

以上就是Spring 事務配置的全過程,完事。

往期內容

Spring IOC 知識點彙總

Spring Aop 的實現方式(XML, 註解)

深刻理解Spring中Bean的生命週期

我是阿福,公衆號「阿福聊編程」做者,對後端技術保持學習愛好者,我會常常更新JAVA技術文章,在進階的路上,共勉!

歡迎你們關注個人公衆號,後臺回覆666,領取Java全套進階實戰課程。

相關文章
相關標籤/搜索