基于AOP的事务管理

使用转账的例子来说明基于AOP的事务管理

1.导入jar包

2.创建数据库

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50725
Source Host           : localhost:3306
Source Database       : springtx

Target Server Type    : MYSQL
Target Server Version : 50725
File Encoding         : 65001

Date: 2019-03-28 16:54:21
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('1', 'xiaoming', '10000');
INSERT INTO `account` VALUES ('2', 'xiaohong', '10000');

 3.编写dao层的代码

package oyb.dao;

public interface IAccountDao {

    public void out(String outer, Integer money);
    public void in(String inner, Integer money);
}

 

package oyb.dao.impl;

import org.springframework.jdbc.core.support.JdbcDaoSupport;
import oyb.dao.IAccountDao;

public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
    @Override
    public void out(String outer, Integer money) {
        String sql = "update account set money = money - ? where username = ?";
        this.getJdbcTemplate().update(sql,money,outer);
    }

    @Override
    public void in(String inner, Integer money) {
        String sql = "update account set money = money + ? where username = ?";
        this.getJdbcTemplate().update(sql,money,inner);


    }
}

4.编写业务层的代码

package oyb.service;

public interface IAccountService {
    public  void transfer(String outer, String in, Integer money);
}
package oyb.service.impl;

import oyb.dao.IAccountDao;
import oyb.service.IAccountService;

public class AccountServiceImpl implements IAccountService {

    //提供set方法,由spring注入
    private IAccountDao accountDao;
    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void transfer(String outer, String inner, Integer money) {
        accountDao.out(outer,money);
        accountDao.in(inner,money);
    }
}

添加db.properties文件

driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///springtx
user=root
password=123456

配置beans.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: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">
    <!--读取db.properties数据-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClass}"/>
        <property name="jdbcUrl" value="${jdbcUrl}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--配置dao-->
    <bean id="accountDao" class="oyb.dao.impl.AccountDaoImpl">
        <!--注入属性-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置service-->
    <bean id="accountService" class="oyb.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
</beans>

测试转账功能是否完好

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import oyb.dao.IAccountDao;
import oyb.service.IAccountService;

public class test {

    @Test
    public  void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        IAccountService accountService = (IAccountService) context.getBean("accountService");
        accountService.transfer("xiaoming","xiaohong",100);
    }
}

测试的结果

基本的条件搭建好了之后,下面来讲基于AOP的事务配置,除了AOP的自动代理,还有工厂代理以及手动管理事务,后两者可作为了解,这里不涉及,主要还是掌握基于AOP的事务管理。

在配置事务管理前,我们可以看下如果业务类中的transfer方法出现了异常,数据库的结果会是怎样的。

我在转账的方法中加了一句int i = 10/0 这段会抛出异常的代码

 可执行完测试的代码之后可以发现,xiaoming的钱虽然减少了,但是并未转入xiaohong的账户中,根据事务管理可知,如果出现了异常,应该回滚。

以上便是没有配置事务管理所会出现的结果

我们让xiaoming的账户恢复到之前的余额

修改beans.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: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">
    <!--读取db.properties数据-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driverClass}"/>
        <property name="jdbcUrl" value="${jdbcUrl}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--配置dao-->
    <bean id="accountDao" class="oyb.dao.impl.AccountDaoImpl">
        <!--注入属性-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置service-->
    <bean id="accountService" class="oyb.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!--配置jdbc事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--AOP的事务配置-->
    <!--1.配置通知
        tx:attributes:配置事务的传播行为以及隔离级别
      隔离级别配置成默认的即可,传播行为也使用默认的required
--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置切面--> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* oyb.service..*.*(..))"></aop:advisor> </aop:config> </beans>

此时在transfer方法中还有int 10/0 这段代码,所以仍存在异常,运行完测试类后,我们查看下数据库

可知事务确实是回滚了。

我们把int i =10/0这句代码删除,在运行测试方法查看下数据库

以上便是基于AOP的事务配置的例子

 

 

 

 



posted @ 2019-03-28 17:40  微命  阅读(187)  评论(0编辑  收藏  举报