spring事务学习(转账案例)(一)

一、创建数据库并插入数据

create database spring_transaction;
use spring_transaction;
create table account(
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money) values('jack',1000);
insert into account(username,money) values('rose',1000);
数据环境

二、无事务下操作数据

1、项目结构及引用的相应jar包

2、创建接口AccountDao及其实现类AccountDaoImpl(实现类继承自JdbcDaoSupport,可以直接获得jdbc模板对象)

package com.hujp.dao;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public interface AccountDao {
    /**
     * 收款(入)
     * @param inUser
     * @param money
     */
    public void in(String inUser,int money);

    /**
     * 汇款(出)
     * @param outUser
     * @param money
     */
    public void out(String outUser,int money);
}
AccountDao
package com.hujp.dao.impl;

import com.hujp.dao.AccountDao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void in(String inUser, int money) {
        this.getJdbcTemplate().update("UPDATE account SET money=money+? WHERE username=?",money,inUser);
    }

    @Override
    public void out(String outUser, int money) {
        this.getJdbcTemplate().update("UPDATE account SET money=money-? WHERE username=?", money, outUser);
    }
}
AccountDaoImpl

3、创建接口AccountService及其实现类AccountServiceImpl(实现类里需要有AccountDao字段,在spring配置中注入)

package com.hujp.service;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public interface AccountService {
    public void transfer(String outUser,String inUser,int money);
}
AccountService
package com.hujp.service.impl;

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

/**
 * Created by JiaPeng on 2015/11/4.
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void transfer(String outUser, String inUser, int money) {
        this.accountDao.out(outUser, money);
        //模拟断电
        //int m=2/0;
        this.accountDao.in(inUser, money);
    }
}
AccountServiceImpl

4、配置文件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: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">
       <!--配置数据源-->
       <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
           <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
           <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property>
           <property name="user" value="root"></property>
           <property name="password" value="hjp123"></property>
       </bean>
       <!--配置Dao-->
       <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl">
           <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!--配置Service-->
       <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl">
              <property name="accountDao" ref="accountDao"></property>
       </bean>
</beans>
applicationContext
package com.hujp;

import com.hujp.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public class TestApp {
    @Test
    public void demo1() {
        String xmlPath = "applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService= (AccountService) applicationContext.getBean("accountService");
        accountService.transfer("jack","rose",100);
    }
}
测试类

 5、代码结构图

二、手动操作事务管理数据库

事务管理主要在service层,所以需要改动两个文件即可,一个是application配置文件,另一个是AccountServiceImpl实现类

在实现类中,事务模板对象执行execute方法,重写事务返回无结果集抽象类TransactionCallbackWithoutResult的抽象方法doInTransactionWithoutResult达到事务管理目的

package com.hujp.service.impl;

import com.hujp.dao.AccountDao;
import com.hujp.service.AccountService;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    //事务操作一般在service层进行操作
    private TransactionTemplate transactionTemplate;

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

    @Override
    public void transfer(final String outUser,final String inUser, final int money) {

        //无结果集操作
        this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.out(outUser, money);
                //模拟断电
                //int m=2/0;
                accountDao.in(inUser, money);
            }
        });
    }
}
AccountServiceImpl
<?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"
       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">
    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property>
        <property name="user" value="root"></property>
        <property name="password" value="hjp123"></property>
    </bean>
    <!--配置Dao-->
    <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置Service-->
    <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <!--一般事务操作在service层进行,所以在service层注入模板-->
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
    <!--事务管理要提供事务管理器,事务是从数据库连接中获得的,而数据库连接是从连接池中获得的-->
    <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>
applicationContext.xml

 三、使用工厂bean创建代理管理事务

继续使用无事务下操作数据库的工程,测试类中accountService对象由代理类创建,并在配置文件配置工厂bean内配置事务

主要改两个文件,一个是测试类,其中获得service对象通过工厂bean获得;另一个是在applicationContext.xml文件中配置工厂bean和事务操作

package com.hujp;

import com.hujp.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by JiaPeng on 2015/11/4.
 */
public class TestApp {
    @Test
    public void demo1() {
        String xmlPath = "applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService= (AccountService) applicationContext.getBean("proxyService");
        accountService.transfer("jack","rose",100);
    }
}
测试类
<?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"
       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">
    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property>
        <property name="user" value="root"></property>
        <property name="password" value="hjp123"></property>
    </bean>
    <!--配置Dao-->
    <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置Service(目标类)-->
    <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!--创建service代理对象之后使用的是代理对象-->
    <bean id="proxyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--确定事务管理器-->
        <property name="transactionManager" ref="transactionManager"></property>
        <!--确定接口-->
        <property name="proxyInterfaces" value="com.hujp.service.AccountService"></property>
        <!--确定目标类-->
        <property name="target" ref="accountService"></property>
        <!--配置事务属性(事务详情)-->
        <property name="transactionAttributes">
            <!--
                prop.key 表示事务详情名称,用于指定哪些方法使用设置的详情
                比如目标类中的transfer方法
                如果是add*,表示以add开头的方法;如果是*表示任意方法
                prop.text 表示当前方法使用具体详情设置
                    格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
                          传播行为     隔离级别   是否只读 异常回滚   异常提交
                例如:PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ表示默认的传播行为和隔离级别
                      PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,readOnly表示只读
                      java.lang.ArithmeticException此异常是在断电程序中出现的
                      PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,+java.lang.ArithmeticException表示异常提交
            -->
            <props>
                <!--<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,readOnly</prop>-->
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,+java.lang.ArithmeticException</prop>
            </props>
        </property>
    </bean>
    <!--管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>
applicationContext
原文地址:https://www.cnblogs.com/hujiapeng/p/4946993.html