spring的事物运用(含AOP管理事物)

事物

事物有四个特性:原子性,一致性,隔离性,持久性。在日常开发对数据库事物操作是非常常见的。如果我们手动写jdbc代码,需要手动调用Connection类的 con.setAutoCommit(false);设置其不自动提交,在try-catch块中显式的调用rollback()函数。

spring对事物的支持

PROPAGATION_REQUIRED如果存在已经一个事务,就支持当前事务。如果没有事务则开启新的事物
PROPAGATION_SUPPORTS如果存在已经一个事务,就支持当前事务。如果没有事务,则非事务的执行。
PROPAGATION_MANDATORY如果已经存在一个事务,就支持当前事务。如果没有一个活动的事务,则抛出异常
PROPAGATION_REQUIRES_NEW总是开启一个新的事务。如果一个事务已经存在,就将这个存在的事务挂起
PROPAGATION_NOT_SUPPORTED总是非事务地执行,并挂起任何已经存在的事务
PROPAGATION_NEVER总是非事务地执行,如果存在一个活动事务,就抛出异常
PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动事务,则按PROPAGATION_REQUIRED属性执行

使用AOP管理事物

我们通过一个例子,看下如何使用aop管理事物。
有2张表,一张商品表,一张销售流水表,卖出商品时需要在流水表中添加一条记录,同时更改商品表中的库存数。

create table good(id int UNSIGNED AUTO_INCREMENT,
    gname varchar(50) NOT NULL COMMENT  '商品名',
    serialNumber varchar(20) NOT NULL COMMENT '商品编码',
    price double(10,2) NOT NULL COMMENT  '价格',
    stock_number int UNSIGNED COMMENT '库存数量',
    create_time datetime,
    primary key(id)
)engine=innodb default charset=utf8;

insert into good (gname,price,create_time) values('牛奶',3.5,10,now());

create table sell_flow(
    id int AUTO_INCREMENT,
    serialNumber varchar(20) NOT NULL COMMENT '商品编码',
    sell_number int UNSIGNED COMMENT '卖出数量',
    create_time datetime,
    primary key(id)
)engine=innodb default charset=utf8;

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:amq="http://activemq.apache.org/schema/core"
    xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/aop   
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd   
        http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd   
        http://www.springframework.org/schema/mvc   
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">  

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


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

        <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
            <property name="driverClassName" value="${driverClassName}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${uname}"/>
            <property name="password" value="${password}"/>
        </bean>

        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>

        <!-- 定义事物管理器-->
        <bean id="transctionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>

        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transctionManger"/>
        </bean>

        <tx:advice id="txAdvice" transaction-manager="transctionManger">
            <tx:attributes>
                <tx:method name="sell" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>

    <aop:config>
            <!--定义切点,匹配sell方法  -->
            <aop:pointcut expression="execution(* com.aop.service.ShopService.sell(..))" id="pointcut"/>
            <!--定义事务管理通知  -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
        </aop:config>

</beans>  
package com.aop.dao;

public interface ShopDao {
    /**
     * 出售方法
     * @param serialNumber 商品编号
     * @param Snumber 卖出数量
     * @return 
     */
    int sellGoods(String serialNumber, int Snumber);

    /**
     *  根据商品编号更新库存
     * @param  serialNumber 商品编号
     * @param Snumber 卖出数量
     * @return
     */
    public int updateStockByName(String serialNumber,int Snumber);
}

商品数据库操作类

package com.aop.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import com.aop.dao.ShopDao;

@Component
public class ShopDaoImpl implements ShopDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public int sellGoods(String serialNumber, int snumber) {
        String sql="insert into sell_flow"
                + "(serialNumber,sell_number,create_time) "
                + "values(?,?,now())";
        Object[] args ={serialNumber,snumber};
        return jdbcTemplate.update(sql, args);

    }

    @Override
    public int updateStockByName(String serialNumber,int snumber) {
        String sql ="update good g set stock_number = g.stock_number-? where serialNumber=?";
        Object[] args ={snumber,serialNumber};
        return jdbcTemplate.update(sql, args);
    }

}
package com.aop.service;

public interface ShopService {
    /**
     * 卖方法
     * @param serialNumber
     * @param Snumber
     */
    void sell(String serialNumber, int Snumber);
}

商品service类

@Service
public class ShopServiceImpl implements ShopService {
    @Autowired
    private ShopDao shopDao;

    @Override
    public void sell(String serialNumber, int Snumber) {

        try {
            shopDao.sellGoods(serialNumber, Snumber);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            Thread.sleep(5000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        shopDao.updateStockByName(serialNumber, Snumber);
    }

}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-aop.xml")
public class springAopTest {



    @Autowired
    ShopService shopService;


    @Test
    public void sell() throws Exception{
        shopService.sell("NO1", 100000);
    }
}

测试,抛出异常,会自动回滚,利用aop我们无需显示的在回滚事物,核心的业务逻辑可以完全分开。

利用注解驱动事物通知

@Transactional(propagation=Propagation.REQUIRED,rollbackFor={Exception.class}
利用@Transactional注解,我们无需配置切点和切面。只需要在注解内指定传播方式,和需要回滚的异常类即可,默认回滚 RuntimeException 和 Error。
在xml文件,以注解驱动通知

<tx:annotation-driven transaction-manager="transctionManger" />
@Service
public class ShopServiceImpl implements ShopService {
    @Autowired
    private ShopDao shopDao;

    @Override
    @Transactional(propagation=Propagation.REQUIRED)
    public void sell(String serialNumber, int Snumber) {

        try {
            shopDao.sellGoods(serialNumber, Snumber);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            Thread.sleep(5000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        shopDao.updateStockByName(serialNumber, Snumber);
    }

}

使用 TransactionTemplate显式的回滚事物

  public void sellTwo(String serialNumber, int Snumber) {

        transactionTemplate.execute(new TransactionCallback<Boolean>() {

            @Override
            public Boolean doInTransaction(TransactionStatus status) {

                try {
                    shopDao.sellGoods(serialNumber, Snumber);
                    shopDao.updateStockByName(serialNumber, Snumber);
                } catch (Exception e) {
                    status.setRollbackOnly();//回滚事物

                    return false;

                }
                return true;
            }
        });


        try {
            shopDao.sellGoods(serialNumber, Snumber);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            Thread.sleep(5000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        shopDao.updateStockByName(serialNumber, Snumber);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值