• 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
  • 相关阅读:
    项目部署
    nginx
    IDEA中Lombok插件的安装与使用
    Git常用命令总结
    CentOS 7 NAT模式上网配置
    一名3年工作经验的java程序员应该具备的技能
    maven 项目加载本地JAR
    linux压缩(解压缩)命令详解
    jdk7与jdk8环境共存与切换
    linux服务器卸载本机默认安装的jdk
  • 原文地址:https://www.cnblogs.com/hujiapeng/p/4946993.html
Copyright © 2020-2023  润新知