Spring事务管理

1、事务回顾,什么是事务,事务的四个特性:

(1)事务是指这样一组操作,这组操作要么全做,要么全不做

(2)四个特性

原子性:是指事务中的操作是不可分割的,这些操作要么全部完成,要么全部不完成。
隔离性:是指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
一致性:是指事务前后数据的完整性要保持一致
持久性:是指一个事务一旦提交,它对数据库中数据的改变就将是永久性的,即使数据库发生故障也不应该对其有任何影响。

2、什么是脏读、不可重复读,幻读

脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的

不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同

幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了,在后来的查询中,第一个事务就会发现某些原来不存在的记录

3、事务的传播行为:

web层 业务层 持久层

 一、编程式事务处理

在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:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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-4.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-4.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="com.zlc" />

    <mvc:annotation-driven />

    <bean id="viewresolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactory" ref="ssf"></property>
        <!-- 扫描com.zlc.dao下所有接口,批量生成实现实例,并交于spring管理 -->
        <property name="basePackage" value="com.zlc.dao"></property>
    </bean>

    <!-- SqlSessionFactoryBean封装了创建SqlSessionFactory组件的过程 -->
    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- 注入Mapper.xml文件位置信息 -->
        <!-- 这样配置就会扫描com/zlc/mapper/下的所有xml文件 -->
        <property name="mapperLocations"
            value="classpath:com/zlc/mapper/*.xml"></property>
    </bean>

    <bean id="dataSource"
        class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="#{dbParams.user}"></property>
        <property name="password" value="#{dbParams.password}"></property>
        <property name="driverClass" value="#{dbParams.driverClass}"></property>
        <property name="jdbcUrl" value="#{dbParams.jdbcUrl}"></property>
    </bean>

    <util:properties location="classpath:db.properties"
        id="dbParams">
    </util:properties>
    
    <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>

在Service层:

package com.zlc.serviceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.zlc.dao.AccountDao;
import com.zlc.service.AccountService;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    
    public boolean transfer(final Integer in, final Integer out, final Double money) {
        transactionTemplate.execute(new TransactionCallback() {
            public Object doInTransaction(TransactionStatus status) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
                return null;
            }
            
        });
        return true;
    }

}

其中粗体字中的内容即被包含为一个事务进行处理。要么全部成功,要么全部不成功,若出现异常则进行回滚。

二、声明式事务处理

(1)使用TransactionProxyFactoryBean进行声明式事务处理

<?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:util="http://www.springframework.org/schema/util"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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-4.0.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-4.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="com.zlc" />

    <mvc:annotation-driven />

    <bean id="viewresolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactory" ref="ssf"></property>
        <!-- 扫描com.zlc.dao下所有接口,批量生成实现实例,并交于spring管理 -->
        <property name="basePackage" value="com.zlc.dao"></property>
    </bean>

    <!-- SqlSessionFactoryBean封装了创建SqlSessionFactory组件的过程 -->
    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入dataSource -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- 注入Mapper.xml文件位置信息 -->
        <!-- 这样配置就会扫描com/zlc/mapper/下的所有xml文件 -->
        <property name="mapperLocations"
            value="classpath:com/zlc/mapper/*.xml"></property>
    </bean>

    <bean id="dataSource"
        class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="#{dbParams.user}"></property>
        <property name="password" value="#{dbParams.password}"></property>
        <property name="driverClass" value="#{dbParams.driverClass}"></property>
        <property name="jdbcUrl" value="#{dbParams.jdbcUrl}"></property>
    </bean>

    <util:properties location="classpath:db.properties"
        id="dbParams">
    </util:properties>
    
    <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>
    
    <!-- 配置业务层的代理 -->
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!-- 配置目标对象 -->
        <property name="target" ref="accountService"></property>
        <!-- 注入事务管理器 -->
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="transactionAttributes">
           <props>
               <!-- 
                  prop格式:
                  key:匹配的方法名,可以使用通配符,如update*
                  * PROPAGATION :事务的传播行为
                  * ISOLATION    :事务的隔离级别
                  * readOnly     :只读
                  * -Exception    :发生哪些异常进行事务回滚
                  * +Exception    :发生哪些异常不进行事务回滚
                -->
               <prop key="transfer">PROPAGATION_REQUIRED</prop>
           </props>
        </property>
    </bean>
</beans>

service层:

package com.zlc.serviceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.zlc.dao.AccountDao;
import com.zlc.service.AccountService;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    public boolean transfer(Integer in, Integer out, Double money) {

        accountDao.outMoney(out, money);
        int i = 1 / 0;
        accountDao.inMoney(in, money);
        return true;

    }

}

Test:

package com.zlc.test;


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

import com.zlc.dao.UserDao;
import com.zlc.entity.User;
import com.zlc.service.AccountService;

public class UserTest {
    
    public static void main(String[] args){
        String conf = "applicationContext.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
        AccountService accountService = ac.getBean("accountServiceProxy",AccountService.class);
        accountService.transfer(1, 2, 100.0);
    }

}

这里改为使用代理类进行访问。

 

posted @ 2018-09-09 19:24  梦里下起了雪  阅读(183)  评论(0编辑  收藏  举报