• [Spring-AOP-XML] 看完了解Spirng中的AOP和XML进行事务管理


    Spring中的AOP进行事务管理有三种方式

    A.自定义事务切面

       利用AspectJ来编写事务,我们一般把这个切面作用在service层中。其他代码在下面

        编写一个Transaction实现类,通过Spring容器进行管理

      Transaction.java

    package com.niit.aspect;
    
    import javax.sql.DataSource;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
    
    /**
     * 文件名称: com.niit.aspect.TransactionAspect.java</br>
     * 初始作者: Administrator</br>
     * 创建日期: 2018-2-5</br>
     * 功能说明: 事务切面类<br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    // @Aspect注解的作用是使得当前的类成为一个切面类
    @Aspect
    public class TransactionAspect {
    
        private DataSource                        ds;
        private DataSourceTransactionManager    manager;
        private TransactionStatus                status;
    
        /**
         * 方法名随意
         */
        // execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?)
        // 拦截com.niit.service包及其子包下所有类中的public声明的任意方法
        @Pointcut("execution(public * com.niit.service.*.*(..))")
        public void method() {
    
            // 该方法的作用仅仅是为了在上面加上一个@Pointcut注解来说明当前的切入点
            // 方法中不需要加任何的代码逻辑
        }
    
        /**
         * 这个方法相当于MethodInterceptor中的invoke方法,实现的是一个环绕通知
         * 方法名随意
         * 
         * @throws Throwable
         */
        // @Around:使得当前的方法成为一个环绕通知方法
        // method():就是前面定义切入点的这个方法名
        // ProceedingJoinPoint对象中封装了被调用的目标方法中的一些信息,也可以用来调用目标方法
        @Around(value = "method()")
        public Object doAroundTask(ProceedingJoinPoint pjp) throws Throwable {
    
            System.out.println("环绕通知的前置部分...");
            // 定义事务对象
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            // 设置事务的隔离级别--在一个事务中只能读取到另外一个事务已经提交的数据
            def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
            // 设置事务的传播方式--当需要事务的时候就主动创建使用事务
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            // def.setReadOnly(true);
    
            // 数据源事务管理器--对数据源中产生的连接对象进行统一管理
            // 参数为数据源对象
            manager = new DataSourceTransactionManager(ds);
            // 事务的状态--事务的提交或回滚等操作都是围绕这个事务状态展开的
            status = manager.getTransaction(def);
            Object result = null;
            result = pjp.proceed(pjp.getArgs());
            System.out.println("环绕通知的后置部分...");
            // 提交事务
            manager.commit(status);
            return result;
        }
    
        // 在目标方法执行中抛出异常时执行的切面--异常通知
        // pointcut:异常通知的切入点,写法同环绕通知中的写法
        // throwing后面的字符串和方法中的参数名是相同的,可以使用这个名字在异常通知的方法中打印和获得目标方法执行过程中相关的异常信息
        @AfterThrowing(pointcut = "method()", throwing = "ex")
        public void doAfterThrow(Exception ex) {
    
            System.out.println("发生了异常...");
            System.out.println(ex.getMessage());
            // 遇到异常--回滚事务
            manager.rollback(status);
        }
    
        public DataSource getDs() {
    
            return ds;
        }
    
        public void setDs(DataSource ds) {
    
            this.ds = ds;
        }
    
        public DataSourceTransactionManager getManager() {
    
            return manager;
        }
    
        public void setManager(DataSourceTransactionManager manager) {
    
            this.manager = manager;
        }
    
        public TransactionStatus getStatus() {
    
            return status;
        }
    
        public void setStatus(TransactionStatus status) {
    
            this.status = status;
        }
    
    }

      

      使用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" 
        xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
        xmlns:jee="http://www.springframework.org/schema/jee" 
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
            
            <!-- 通过util方式来读取properties配置文件 -->
            <util:properties id="dbConfig" location="classpath:jdbc.properties"/>
            
            <!-- 定义dbcp数据源 -->
            <bean id="ds" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
                <property name="driverClassName" value="#{dbConfig.driver}"></property>
                <property name="url" value="#{dbConfig.url}"></property>
                <property name="username" value="#{dbConfig.username}"></property>
                <property name="password" value="#{dbConfig.userpwd}"></property>
            </bean>
            
            <!-- Spring JDBC相关对象 -->
            <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="ds"></property>
            </bean>
            <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
                <constructor-arg index="0" ref="ds"></constructor-arg>
            </bean>
            
    <!--
            开启AspectJ的自动代理 当Spring容器在初始化时,会通过@Aspect注解找到切面类, 再根据 <aop:aspectj-autoproxy/>配置,将切面自动作用到目标方法上
    --> <aop:aspectj-autoproxy/> <!-- AspectJ事务管理切面 --> <bean id="txAspect" class="com.stu.aspect.TransactionAspect"> <property name="ds" ref="ds"></property> </bean> <bean id="bankDao" class="com.stu.dao.impl.BankDaoImpl"> <property name="jdbcTempalte" ref="jdbcTemplate"></property> </bean> <bean id="bankService" class="com.niit.service.impl.BankServiceImpl"> <property name="bankDao" ref="bankDao"></property> </bean> </beans>

     

    B,Transaction注解

        利用AspectJ来编写事务,用银行的转账来进行模拟。

        当一个用户从自己的账号转出金额到另一个用户账户上,两个账户的金额都应该有变化,有一个失败则全部失败。先建立Bank有关的Dao和Service层,以及对应的实现层。TransactionAspect为事务类

        

    1.写一个类,充当为事务切面类,一般对于事务的管理,选择放在Service层中。添加了@Transaction注解

        TransactionAspect.java

    package com.stu.aspect;
    
    import javax.sql.DataSource;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
    
    /**
     * 文件名称: com.stu.aspect.TransactionAspect.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明: 事务切面类 <br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    // 1.加上@Aspect注解,表示这个类是一个切面类
    @Aspect
    public class TransactionAspect {
    
        /**
         * 定义为全局的私有属性,方便共享
         */
        private DataSource                        ds;
        private DataSourceTransactionManager    manager;
        private TransactionStatus                status;
    
        /**
         * 2.写一个方法,加上@Pointcut注解表示为切入点,并且配置@Pointcut中的其他参数:
         * 
         * @Pointcut(execution(modifiers-pattern? ret-type-pattern
         *                                        declaring-type-pattern?name-pattern(param-pattern)throws-pattern?))<br />
         *                                        execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
         */
        @Pointcut("execution(public * com.stu.service.*.*(..))")
        public void method() {
    
            // 该方法的作用仅仅是为了在上面加上一个@Pointcut注解来说明当前的切入点
            // 方法中不需要加任何的代码逻辑
        }
    
        /**
         * 3.添加一个环绕通知,使用@Around注解。配置切入点方法,value为刚刚定义的切入点方法名称
         * 这个方法相当于MethodInterceptor中的invoke方法,实现的是一个环绕通知
         * 
         * @throws Throwable
         */
        @Around(value = "method()")
        public Object doAroundTest(ProceedingJoinPoint pjp) throws Throwable {
    
            System.out.println("---TransactionAspect.doAroundTest()---前置通知---");
            /**
             * 4.定义事务对象并设置事务的隔离级别和传播方式
             */
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            // 隔离级别
            def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
            // 传播方式
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    
            /**
             * 5.数据源事务管理器--对数据源中产生的连接对象进行统一管理
             */
            manager = new DataSourceTransactionManager(ds);
            // 事务的状态,事务的提交或回滚操作都是围绕这个事务状态展开的
            status = manager.getTransaction(def);
            Object result = null;
            result = pjp.proceed(pjp.getArgs());
            System.out.println("---doAroundTest()---后置通知---");
            /**
             * 6. 提交
             */
            manager.commit(status);
    
            return result;
        }
    
        /**
         *7.使用@AfterThrowing注解添加一个在目标执行中抛出异常执行的切面--异常通知
         *pointcut:异常通知的切入点
         *throwing:后面的字符串和方法中的参数名是相同的,使用这个名字在异常通知中打印目标的异常信息
         */
        @AfterThrowing(pointcut = "method()", throwing = "ex")
        public void doAfterThorw(Exception ex) {
    
            System.out.println("发生了异常");
            System.out.println(ex.getMessage());
            /**
             * 8.如果发生异常则进行回滚操作
             */
            manager.rollback(status);
        }
    
        public DataSource getDs() {
    
            return ds;
        }
    
        public void setDs(DataSource ds) {
    
            this.ds = ds;
        }
    
        public DataSourceTransactionManager getManager() {
    
            return manager;
        }
    
        public void setManager(DataSourceTransactionManager manager) {
    
            this.manager = manager;
        }
    
        public TransactionStatus getStatus() {
    
            return status;
        }
    
        public void setStatus(TransactionStatus status) {
    
            this.status = status;
        }
    
    }

     

    @Pointcut注解的方法就是切入点,

    //@Pointcut(execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)throws-pattern?))
    //execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
    @Pointcut("execution(public * com.stu.service.*.*(..))")
    execution() 表达式的主体
    第一个“*”符号 表示返回值的类型任意
    com.stu.service
    AOP所切的服务的包名,即,需要进行横切的业务类
    包名后面的“.*” 表示当前包及子包
    第二个“.*” 表示类名,*即所有类
    .*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型

    2.补充完业务和dao层中的所有逻辑

      BankDao.java

    package com.stu.dao;
    
    /**
     * 文件名称: com.stu.dao.BankDao.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明:bank的Dao层 <br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    public interface BankDao {
    
        /**
         * 方法描述: [修改卡里余额]<br/>
         * 初始作者: Administrator<br/>
         * 创建日期: 2018-2-5-下午03:08:31<br/>
         * 开始版本: 2.0.0<br/>
         * =================================================<br/>
         * 修改记录:<br/>
         * 修改作者 日期 修改内容<br/>
         * ================================================<br/>
         * 
         * @param cardId
         *            银行卡卡号
         * @param money
         *            转账金额
         * @return
         *         int 修改条数
         */
        int editBalance(int cardId, int money);
    }

        

        BankDaoImpl.java

    package com.stu.dao.impl;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    
    import com.stu.dao.BankDao;
    
    /**
     * 文件名称: com.stu.dao.impl.BankDaoImpl.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明: Bank的Dao实现类<br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    public class BankDaoImpl implements BankDao {
    
        private JdbcTemplate    jdbcTemplate;
    
        @Override
        public int editBalance(int cardId, int money) {
    
            return jdbcTemplate.update("update bank set balance=balance+? where cardid=?", new Object[] {
                    money, cardId
            });
        }
    
        public JdbcTemplate getJdbcTemplate() {
    
            return jdbcTemplate;
        }
    
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    
            this.jdbcTemplate = jdbcTemplate;
        }
    
    }

        

        BankService.java

    package com.stu.service;
    
    /**
     * 文件名称: com.stu.service.BankService.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明: Bank的Service层 <br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    public interface BankService {
    
        /**
         * 方法描述: [转账的操作]<br/>
         * 初始作者: Administrator<br/>
         * 创建日期: 2018-2-5-下午03:07:40<br/>
         * 开始版本: 2.0.0<br/>
         * =================================================<br/>
         * 修改记录:<br/>
         * 修改作者 日期 修改内容<br/>
         * ================================================<br/>
         * 
         * @param form
         * @param to
         * @param money
         *            void
         */
        void tarns(int form, int to, int money);
    }

        BankServiceImpl.java

    package com.stu.service.impl;
    
    import java.io.FileNotFoundException;
    
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.stu.dao.BankDao;
    import com.stu.service.BankService;
    
    /**
     * 文件名称: com.stu.service.impl.BankServiceImpl.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明: BankService层的实现类<br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    @Transactional
    public class BankServiceImpl implements BankService {
    
        private BankDao    bankDao;
    
        /**
         * isolation: 隔离级别
         * propagation: 传播行为
         * rollbackFor: 指定什么类型的异常才回滚,默认为运行时异常
         * noRollbackFor: 指定发生什么类型的异常不会滚,默认遇到检查异常不会自动回滚
         */
        @Override
        @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = {
                FileNotFoundException.class, NullPointerException.class, NumberFormatException.class })
                public void tarns(int form, int to, int money) {
    
            try {
                bankDao.editBalance(form, -money);
                bankDao.editBalance(to, money);
            } catch (Exception e) {
                e.printStackTrace();
                // Service中的异常一定要向上抛出,否则@Transactional对应的注解解析器,无法捕获到 对应的切入点(被@Transactional注解标记的方法)抛出的异常,无法进行事务的回滚操作
                throw new RuntimeException(e);
            }
        }
    
        public BankDao getBankDao() {
    
            return bankDao;
        }
    
        public void setBankDao(BankDao bankDao) {
    
            this.bankDao = bankDao;
        }
    
    }

      因为切面的切入点是该类中的方法上,所以使用Transaction注解

      Demo02.java

    package com.stu.demo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.stu.service.BankService;
    
    /**
     * 文件名称: com.stu.demo.Demo02.java<br/>
     * 初始作者: Administrator<br/>
     * 创建日期: 2018-2-5<br/>
     * 功能说明: AspectJ事务操作 <br/>
     * =================================================<br/>
     * 修改记录:<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     * Copyright (c) 2010-2011 .All rights reserved.<br/>
     */
    public class Demo02 {
    
        public static void main(String[] args) {
    
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContextForAspectJ.xml");
            BankService bankService = ac.getBean("bankService", BankService.class);
            //从 卡号1 向 卡号2 中转账100块
            bankService.tarns(1, 2, 100);
        }
    }

        applicationContextForAspectJ.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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
    
        <!-- 通过 XML配置文件读取jdbc.properties中的数据库配置信息 -->
        <util:properties id="dbConfig" location="classpath:jdbc.properties"></util:properties>
    
        <!-- 定义jdbc的数据源 -->
        <bean id="ds" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
            <property name="driverClassName" value="#{dbConfig.driver}"></property>
            <property name="url" value="#{dbConfig.url}"></property>
            <property name="username" value="#{dbConfig.username}"></property>
            <property name="password" value="#{dbConfig.userpwd}"></property>
        </bean>
    
        <!-- 配置Spring中的JDBC对象 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="ds"></property>
        </bean>
        
        <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg index="0" ref="ds"></constructor-arg>
        </bean>
        

    <!-- 使用AspectJ事务管理 --> <!-- 开启AspectJ的自动代理 当Spring容器在初始化时,通过@Aspect注解找到切面类 根据<aop:aspectj-autoproxy />配置,将切面自动作用到目标方法上 --> <aop:aspectj-autoproxy /> <!-- 使用AspecJ事务管理切面 --> <bean id="txAspect" class="com.stu.aspect.TransactionAspect"> <property name="ds" ref="ds"></property> </bean> <bean id="bankDao" class="com.stu.dao.impl.BankDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="bankService" class="jdbcTemplate"></bean> </beans>

     


     

    C.编程式事务,

      不推荐使用,事务管理和业务耦合度高,侵入性高

      使用编程式事务时,Spring提供以下两种事务管理的API(推荐使用前者)

      1,使用TransactionTemplate

      2,直接使用一个PlatformTransactionManager实现,(但是一般使用DataSourceTransactionManager)

      TransactionTemplate与JdbcTemplate等模板类的使用风格相似,它也使用回调机制,将事务代码和业务代码分离,这样便于开发者把精力集中在具体的业务编程上。

      

      applicationContext.xml配置文件

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="ds"/>
    </bean>
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="txManager"/>
            <property name="propagationBehavior" value="0"></property>
            <property name="isolationLevel" value="2"></property>
            <property name="readOnly" value="true"></property>
    </bean>


    (1)如果需要返回值,则传递TransactionCallback匿名内部类

        public boolean trans1(final int money, int from, int to) {
    
            Boolean result = null;
            try {
                result = transactionTemplate.execute(new TransactionCallback<Boolean>() {
    
                    @Override
                    public Boolean doInTransaction(TransactionStatus status) {
    
                        try {
                            bankDao.updateBalance(-money, 1);
                            if (1 == 1) {
                                throw new RuntimeException("转账过程中出错了!");
                            }
                            bankDao.updateBalance(money, 2);
                            return true;
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            status.setRollbackOnly();
                            return false;
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }

    测试:

        public static void main(String[] args) {
    
            ApplicationContext ac =
                new ClassPathXmlApplicationContext("applicationContext.xml");
            BankService bankService = ac.getBean("bankService", BankService.class);
            boolean result = bankService.trans4(50, 1, 2);
            System.out.println(result);
            ((AbstractApplicationContext) ac).close();
        }

    (2)如果不需要返回值,可以创建一个TransactionCallbackWithoutResult匿名类

    @Override
        public boolean trans2(final int money, int from, int to) {
            try {
                transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                    @Override
                    protected void doInTransactionWithoutResult(TransactionStatus status) {
                        try {
                            bankDao.updateBalance(-money, 1);
                            if (1 == 1) {
                                throw new RuntimeException("转账过程中出错了!");
                            }
                            bankDao.updateBalance(money, 2);
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            status.setRollbackOnly();
                        }
                    }
                });
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }

    使用XML配置事务

    在上面的基础上进行修改

    applicationContextForXML.xml

        <!-- 通过 XML配置文件读取jdbc.properties中的数据库配置信息 -->
        <util:properties id="dbConfig" location="classpath:jdbc.properties"></util:properties>
    
        <!-- 定义jdbc的数据源 -->
        <bean id="ds" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
            <property name="driverClassName" value="#{dbConfig.driver}"></property>
            <property name="url" value="#{dbConfig.url}"></property>
            <property name="username" value="#{dbConfig.username}"></property>
            <property name="password" value="#{dbConfig.userpwd}"></property>
        </bean>
    
        <!-- 配置Spring中的JDBC对象 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="ds"></property>
        </bean>
    
        <bean id="namedJdbcTemplate"
            class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg index="0" ref="ds"></constructor-arg>
        </bean>
    
        <!-- 使用XML配置文件进行事务管理 -->
        <!-- 配置事务相关的属性 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!-- 配置事务相关的属性 -->
                <!--
                    name:方法名 propagation:隔离级别 isolation:传播方法 rollback-for:遇到什么异常回滚
                    no-rollback-for:遇到什么异常不回滚
                -->
                <tx:method name="trans*" propagation="REQUIRED" isolation="READ_COMMITTED"
                    rollback-for="java.lang.RuntimeException" />
    
                <!--
                    <tx:method name="trans*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="java.lang.RuntimeException"/> 
                    <tx:method name="trans*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="java.lang.RuntimeException"/>
                -->
            </tx:attributes>
        </tx:advice>
  • 相关阅读:
    JQuery框架中使用blockUI制作自定义的漂亮的网页提示框
    PHP树形菜单一次展开一个子项目,可以记录打开的项目,刷新后不变
    第一次面试
    东软的校园招聘笔试
    fscommand
    从 ActionScript 中调用外部代码
    GCC 参数详解
    flash build找不到调试版plashplayer的解决办法
    C# winform与 flash as 的交互通讯
    LLVM 与 Clang 介绍
  • 原文地址:https://www.cnblogs.com/x-you/p/8419216.html
Copyright © 2020-2023  润新知