【 Spring 事务案例 】—— 转账

创建数据库表

CREATE DATABASE IF NOT EXISTS spring CHARACTER SET utf8;
USE spring;
create table account(
  id int primary key auto_increment,
  username varchar(50),
  money int
);

insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');

导入 jar 包

  • 核心:4+1
  • aop : 4 (aop联盟、spring aop、aspectj规范、spring aspect)
  • 数据库:2 (jdbc/tx)
  • 驱动:mysql
  • 连接池:c3p0
    在这里插入图片描述
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.ys</groupId>
    <artifactId>Spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring 核心包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- Spring aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>

        <!-- 数据库 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.19.RELEASE</version>
        </dependency>

        <!-- MySQL 驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Dao 层

package cn.ys.dao;

public interface AccountDao {

    //扣钱
    public void out(String outer,Integer money);

    //进帐
    public void in(String inner,Integer money);

}

package cn.ys.dao;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

    public void out(String outer, Integer money) {
        String sql = "update account set money = money - ? where username = ?";
        getJdbcTemplate().update( sql, money, outer);
    }

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

Service 层

package cn.ys.service;

public interface AccountService {

    /**
     * 转账
     * @param outer 转出帐号
     * @param inner 转入帐号
     * @param money 转入金额
     */
    public void transfer(String outer,String inner,Integer money);

}

package cn.ys.service;

import cn.ys.dao.AccountDao;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService {

    // 由spring注入
    private AccountDao accountDao;

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

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

}

Spring 的配置

配置c3p0数据源->dao -> service

db.properties

driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://yangnanxi.cn:3306/spring
user=yang
password=123456
<?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"
       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">

    <!-- 读取db.properties数据-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <!-- 配置c3p0数据源
    注:dbcp和c3po的 数据库连接的参数的属性名是不一样
    please attention。。。。。
    -->
    <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="cn.ys.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

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

</beans>

测试转帐

package cn.ys.spring;

import cn.ys.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testSpring {

    @Test
    public void testSpring() {

        //转帐测试
        //获取Service
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        AccountService accountService = (AccountService) context.getBean("accountService");
        accountService.transfer("jack","rose",100);

    }

}

方式一:手动管理事务【了解】

spring 底层使用 TransactionTemplate 事务模板进行操作。

操作
1.service 需要获得 TransactionTemplate
2.spring 配置模板,并注入给service
3.模板需要注入事务管理器
4.配置事务管理器:DataSourceTransactionManager ,需要注入DataSource

了解底层即可,因为以后都是通过aop来配置事务

修改Service

package cn.ys.service;

import cn.ys.dao.AccountDao;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService {

    // 由spring注入
    private AccountDao accountDao;

    //Spring配置事务模版【由spring注入】
    private TransactionTemplate transactionTemplate;

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

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transfer(final String outer, final String inner, final Integer money) {
        this.accountDao.out(outer, money);
        this.accountDao.in(inner, money);

        this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                //扣钱
                accountDao.out( outer, money);
                //int i = 10 / 0;
                //进帐
                accountDao.in( inner, money);
            }

        });
    }

}

在这里插入图片描述

修改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"
       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">

    <!-- 读取db.properties数据-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <!-- 配置c3p0数据源
    注:dbcp和c3po的 数据库连接的参数的属性名是不一样
    please attention。。。。。
    -->
    <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="cn.ys.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--配置dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置事务模版-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <!--事务管理器-->
        <property name="transactionManager" ref="txManager"></property>
    </bean>

    <!--配置service-->
    <bean id="accountService" class="cn.ys.service.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <!-- 配置事务模版-->
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>

</beans>

在这里插入图片描述

方式二:工厂 bean 生成代理:半自动

Spring提供 管理事务的代理工厂bean TransactionProxyFactoryBean

修改spring配置文件

transactionAttributes:事务详情
prop.key :确定哪些方法使用当前事务配置
    prop.text:用于配置事务详情
	格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
	传播行为		 隔离级别	      是否只读	异常回滚	      异常提交
<?xml version="1.0" encoding="UTF-8"?>
<!--xmlns xml namespace:xml命名空间-->
<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"
       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">

    <!-- 读取db.properties数据-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <!-- 配置c3p0数据源
    注:dbcp和c3po的 数据库连接的参数的属性名是不一样
    please attention。。。。。
    -->
    <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="cn.ys.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--配置dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

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

    <!-- 配置工厂代理-->
    <bean id="proxyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--接口-->
        <property name="proxyInterfaces" value="com.gyf.service.IAccountService"></property>
        <!--目标对象-->
        <property name="target" ref="accountService"></property>
        <!--切面对象:Spring做,就不用写-->

        <!-- 事务管理器-->
        <property name="transactionManager" ref="txManager"/>

        <!--transactionAttributes:事务属性/详情配置
            key:写方法名
            value写 事务配置
            格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
	      传播行为		 隔离级别	      是否只读	异常回滚 异常提交
        -->
        <property name="transactionAttributes">
            <props>
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop>
                <prop key="add">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
                <prop key="delete">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
                <prop key="update">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
                <prop key="find">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop>
            </props>
        </property>
    </bean>
</beans>

在这里插入图片描述

测试:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42112635/article/details/88022011
今日推荐