Spring框架简介⑩

事务的特性(ACID):

A: Atomic 原子性

表示组成一个事务的多个对数据库的操作为一个不可分割的单元, 只有所有的操作都成功才算成功, 整个事务才会提交, 其中任何一个操作失败了都会导致整个操作失败, 事务则会回滚

C: Consistency 一致性

事务操作成功后, 数据库所处的状态和业务规则是一致(不变)的, 如果A账户给B账户汇100, 则A账户要减去100, B账户要加上100 两个账户的总额是不变的

I: Isolation 隔离性

在多个对数据库操作相同的数据并发时, 不同的事务有自己的数据空间, 事务与事务之间不受干扰(不是绝对的), 干扰程度受数据库或者操作事务的隔离级别来决定, 隔离级别越高, 干扰就越低, 数据的一致性就越好, 而并发性则越差.

D: Durability 持久性

一旦事务提交成功, 数据就被持久化到数据库, 不可以回滚, 重启/关机都不会丢失数据了.

原子性由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: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-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <!-- 配置属性文件的位置 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!-- 配置数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    
        <!-- 采用${xxx}的形式读取属性文件中对应key的内容 -->
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${uname}"></property>
        <property name="password" value="${pword}"></property>
        <!-- 初始化连接数 -->
        <property name="initialSize" value="${initialSize}"></property>
        <!-- 最大连接数 -->
        <property name="maxActive" value="${maxActive}"></property>
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="${maxIdle}"></property>
        <!-- 最小空闲连接数 -->
        <property name="minIdle" value="${minIdle}"></property>
    </bean>
    
    <bean id="orderDao" class="com.rl.spring.dao.impl.OrderDaoImpl">
        <property name="ds" ref="dataSource"></property>
    </bean>
    <bean id="detailDao" class="com.rl.spring.dao.impl.DetailDaoImpl">
        <property name="ds" ref="dataSource"></property>
    </bean>
    
    <bean id="orderService" class="com.rl.spring.service.impl.OrderServiceImpl">
        <property name="orderDao" ref="orderDao"></property>
    </bean>
    
    <bean id="detailService" class="com.rl.spring.service.impl.DetailServiceImpl">
        <property name="orderDao" ref="orderDao"></property>
        <property name="detailDao" ref="detailDao"></property>
    </bean>
    
    <!-- 定义事务管理器 -->    
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置事务管理的注解驱动 -->
    <tx:annotation-driven transaction-manager="txManager"/>
</beans>

下面只粘贴实现类的代码

OrderDaoImpl:

package com.rl.spring.dao.impl;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.rl.spring.dao.OrderDao;
import com.rl.spring.model.Order;

public class OrderDaoImpl implements OrderDao {

    private DataSource ds;
    
    private JdbcTemplate jt;
    
    public void setDs(DataSource ds) {
        this.ds = ds;
        this.jt = new JdbcTemplate(ds);
    }

    @Override
    public int saveOrder(Order order) {
        String sql = "insert into t_order values(null, ?)";
        jt.update(sql, new Object[] {order.getTotalPrice()});
        return jt.queryForInt("SELECT LAST_INSERT_ID()");//该行代码的作用是让数据库返回主键
    }
}

DetailDaoImpl

package com.rl.spring.dao.impl;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.rl.spring.dao.DetailDao;
import com.rl.spring.model.Detail;
import com.rl.spring.model.Order;

public class DetailDaoImpl implements DetailDao {

    private DataSource ds;
    
    private JdbcTemplate jt;
    
    public void setDs(DataSource ds) {
        this.ds = ds;
        this.jt = new JdbcTemplate(ds);
    }

    @Override
    public void saveDetail(Detail detail) {
        String sql = "insert into t_detail values(null, ?, ?, ?)";
        jt.update(sql, new Object[] {detail.getItemName(), detail.getQuantity(), detail.getOrderId()});
    }
}

OrderServiceImpl(较简单, 省略粘贴上来)

DetailServiceImpl:

package com.rl.spring.service.impl;

import org.springframework.transaction.annotation.Transactional;

import com.rl.spring.dao.DetailDao;
import com.rl.spring.dao.OrderDao;
import com.rl.spring.model.Detail;
import com.rl.spring.model.Order;
import com.rl.spring.service.DetailService;

public class DetailServiceImpl implements DetailService {

    DetailDao detailDao;
    
    OrderDao orderDao;
    
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    public void setDetailDao(DetailDao detailDao) {
        this.detailDao = detailDao;
    }

    @Transactional//事务管理注解
    @Override
    public void saveOrderAndDetail(Order order, Detail detail) {
        Integer orderId = orderDao.saveOrder(order);
        detail.setOrderId(orderId);
        int i = 1/0;//设置运行期异常, 由于配置了Transactional注解, 所以事务会全部回滚
        detailDao.saveDetail(detail);
    }
}

测试代码:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.Detail;
import com.rl.spring.model.Order;
import com.rl.spring.service.DetailService;
import com.rl.spring.service.OrderService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    OrderService orderService;
    
    @Autowired
    DetailService detailService;
    
    @Test
    public void test() {
        Order order = new Order();
        order.setTotalPrice(100);
        
        Detail detail = new Detail();
        detail.setItemName("HUAWEI");
        detail.setQuantity(1);
        detailService.saveOrderAndDetail(order, detail);
    }
}

@Transactional注解的本质是事务的传播特性, 下面详讲事务的传播特性

Spring的传播特性

Required传播特性(80%以上使用该传播特性)

业务方法需要在一个事务中运行, 如果一个方法已经处在一个事务中那么就加入到这个事务中, 否则就会创建一个新事务

如下图:

传播特性可配置:

Never传播特性(极少使用):

指定的业务方法绝对不能在事务中运行, 如果在事务中运行了, 则会抛异常, 只有业务方法没有事务才会正常执行.

MANDATORY传播特性:

与Never相反, 只能在一个已经存在的事务中执行, 不能自己发起事务, 如果业务方法没有事务的情况下, 则抛异常

SUPPORTS传播特性:

如果业务方法已经在某个事务中被调用, 则业务方法就成为事务的一部分, 如果业务方法没有在某个事务中被调用, SUPPORTS也支持该业务方法的执行(一句话, 开事务我就用事务, 不开事务我就不用事务, 但都可以执行)

NOT_SUPPORTED传播特性:

永远不支持事务(在有事务中该事务会被挂起)

REQUIRES_NEW传播特性:

永远使用自己创建的事务(如果已经存在事务则挂起它, 自己新创建), 假如自己new出来的这个事务回滚了, 是不会影响到另一个被挂起的事务的.

NESTED传播特性:

主要区分于内外部事务, 如果内部事务做回滚, 是不会影响到外部事务的(因为NESTED会设置一个事务保存点, 回滚到该保存点后继续执行外部事务); 而如果是外部事务做回滚, 该内外部事务全部回滚.

这点跟REQUIRES_NEW有区别, REQUIRES_NEW是不管是否内外部事务都互不影响.

====================================================

Spring系列暂时写到这里, 后续抽时间更一下事务的隔离级别, 接下来会更Hibernate系列.

猜你喜欢

转载自blog.csdn.net/ip_JL/article/details/81509852