实现spring事务的四种方式

用一个银行账号转钱的案例来说明spring事务的实现。
在转钱过程中,一个账号钱增加,另一个减少,那么当有异常产生时,就会出现钱转丢了的现象
一个减少了,而另一个没有增加,这个时候就需要把这两个行为绑定到一起,要么同时发生,要么都不发生
这就用到了事务,事务就是指在逻辑上的一组操作,这组操作要么全部成功,要么全部失败

实现spring事务的四种方式分别为:
(1)编程式事务管理:需要手动编写代码,在实际开发中很少使用
(2)声明式事务管理:
(2.1)基于TransactionProxyFactoryBean的方式,需要为每个进行事务管理的类做相应配置
(2.2)基于AspectJ的XML方式,不需要改动类,在XML文件中配置好即可
(2.3)基于注解的方式,配置简单,需要在业务层类中添加注解

(2.2)和(2.3)在开发中使用比较多,前者配置一目了然,可以在XML文件中得到所有信息,后者配置简单方便

需要做的一些准备工作:

1.在数据库中新建一张account数据表

SQL脚本:

CREATE TABLE `account` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(20) NOT NULL,

  `money` double DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `account` VALUES (‘1‘, ‘aaa‘, ‘1000‘);

INSERT INTO `account` VALUES (‘2‘, ‘bbb‘, ‘1000‘);

INSERT INTO `account` VALUES (‘3‘, ‘ccc‘, ‘1000‘);

2.需要引入的Jar包

3.为数据库连接准备的配置文件- jdbc.properties

使用c3p0数据库连接池

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://127.0.0.1\:3306/test
jdbc.username=root
jdbc.password=

4.创建两个接口
AccountDao:数据库操作
public interface AccountDao {public void outMoney(String out,Double money);public void inMoney(String in,Double money);
}

AccountService:逻辑处理操作
public interface AccountService {/*** * @param out 转出账号* @param in  转入账号* @param money 转账金额*/public void transfer(String out,String in,Double money);
}

5.创建以上两个接口的实现类

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

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

    public void outMoney(String out, Double money) {

        String sql="update account set money=money-? where name=?";

        this.getJdbcTemplate().update(sql,money,out);

    }

    public void inMoney(String in, Double money) {

        String sql="update account set money=money+? where name=?";

        this.getJdbcTemplate().update(sql,money,in);

    }

}
public class AccountServiceImpl implements AccountService{

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {

        this.accountDao = accountDao;

    }

    public void transfer(String out,String in,Double money) {

        accountDao.outMoney(out, money);

        accountDao.inMoney(in, money);    

    }        

}

6.测试类(使用spring加JUnit4整合测试)

import javax.annotation.Resource;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")//引入xml文件

public class TestDemo1 {

    @Resource(name="accountService")//得到bean id为accountService的对象

    private AccountService accountService;

    @Test

    public void demo1(){

        accountService.transfer("aaa", "bbb", 200d);

    }    

}

7.xml文件 - 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"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xmlns:task="http://www.springframework.org/schema/task"

     xsi:schemaLocation="http://www.springframework.org/schema/beans

         http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

         http://www.springframework.org/schema/context

         http://www.springframework.org/schema/context/spring-context-3.1.xsd

         http://www.springframework.org/schema/aop

         http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

         http://www.springframework.org/schema/tx

         http://www.springframework.org/schema/tx/spring-tx-3.1.xsd

         http://www.springframework.org/schema/task

         http://www.springframework.org/schema/task/spring-task-3.1.xsd">

    <!-- 引入外部的配置文件 -->

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- 配置c3p0连接池 -->

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

        <property name="driverClass" value="${jdbc.driverClass}"/>

        <property name="jdbcUrl" value="${jdbc.url}"/>

        <property name="user" value="${jdbc.username}"/>

        <property name="password" value="${jdbc.password}"/>

    </bean>

    <bean id="accountService" class="demo1.AccountServiceImpl">

        <property name="accountDao" ref="accountDao"/>

    </bean>

    <bean id="accountDao" class="demo1.AccountDaoImpl">

        <property name="dataSource" ref="dataSource"/>

    </bean>

</beans>

代码实现方式:

 

(1)编程式事务管理

ServiceImpl类:

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService{

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {

        this.accountDao = accountDao;

    }

    /**

     * 注入事务管理的模板

     * 在xml文件中添加Property

     * <property name="transactionTemplate" ref="transactionTemplate"/>

     */

    private TransactionTemplate transactionTemplate;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

        this.transactionTemplate = transactionTemplate;

    }

    public void transfer(final String out,final String in,final Double money) {

        /**

         * 在这里面进行事务操作

         * 因为需要在匿名内部类中使用参数,所以给参数加上final关键字

         */

        transactionTemplate.execute(new TransactionCallbackWithoutResult(){

            @Override

            protected void doInTransactionWithoutResult(

                    TransactionStatus transactionStatus) {

                accountDao.outMoney(out, money);

                accountDao.inMoney(in, money);        

            }    

        });

    }        

}

xml文件中需要配置事务管理器,无论使用哪一种方式,都需要在xml文件中配置事务管理器,将事务管理器注入到模板中,而该模板又会自动注入到accountService中,业务逻辑处理都放在了execute方法中。

<!--spring事务编程式 -->

<!-- 配置事务管理器  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

<!-- 定义事务管理的模板 :Spring为了简化事务管理的代码而提供的类  -->

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

    <property name="transactionManager" ref="transactionManager"/>

</bean> 

在DaoImpl类中,继承了JdbcDaoSupport类,可以省去jdbc复杂的代码
在XML文件配置中,注入dataSource用来获取数据库的连接

(2.1)基于TransactionProxyFactoryBean的方式
采用spring-aop的方式,需要用到代理模式

XML文件:

<!-- 配置事务管理器  -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

<!-- 配置业务层代理: -->

<bean id="accountServiceProxy" 

    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    <!-- 配置目标对象 -->

    <property name="target" ref="accountService"/>

    <!-- 注入事务管理器  -->

    <property name="transactionManager" ref="transactionManager"/>

    <!-- 注入事务属性 -->

    <property name="transactionAttributes">

        <props>

        <!-- 

           格式 ,key为方法名称

           PROPAGATION:事务的传播行为

           ISOLATION:事务的隔离级别

           readOnly:只读

           Exception:发生哪些异常,回滚事务

           +Exception:发生哪些异常不回滚

         -->

            <prop key="transfer">PROPAGATION_REQUIRED</prop>

        </props>

    </property>

</bean>

在测试类中需自动注入的bean-id就不再是accountService了,而是代理类accountServiceProxy
此时代理类和被代理类实现了共同的接口,AccountService,有关代理模式请看:代理模式
@Resource(name="accountServiceProxy")
private AccountService accountService;

(2.2)基于AspectJ的XML方式

XML文件:

<!-- 配置事务管理器 -->

<bean id="transactionManager" 

    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

<!-- 配置的事务的通知 -->

<tx:advice id="txAdvice" transaction-manager="transactionManager">

    <tx:attributes>

        <!-- 

        propagation:事务传播行为

        isolation:事务隔离级别

        read-only:只读

        rollback-for:发生哪些异常回滚

        no-rollback-for:发生哪些异常不回滚

        timeout:有效期

         -->

        <tx:method name="transfer" propagation="REQUIRED"/>

    </tx:attributes>

</tx:advice>

<!-- 配置切面 -->

<aop:config>

    <aop:pointcut expression="execution(* demo3.AccountService.*(..))" id="pointcut1"/>

    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>

</aop:config>

(2.3)基于注解的方式,配置简单,需要在业务层类中添加注解

<!-- 配置事务管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

<!-- 开启注解事务 -->

<tx:annotation-driven transaction-manager="transactionManager"/>

在serviceImpl类中需要添加注解,参数和上面同理

@Transactional(propagation=Propagation.REQUIRED)

我这儿整理了比较全面的JAVA相关的面试资料,


需要领取面试资料的同学,请加群:473984645

原文地址:https://www.cnblogs.com/1013wang/p/12307671.html

时间: 2024-12-23 12:33:45

实现spring事务的四种方式的相关文章

(转)spring事务管理几种方式

转自:http://blog.csdn.net/jeamking/article/details/43982435 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. 总结如下: Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是

[转] spring事务管理几种方式

前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. 总结如下: Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSource.TransactionManager这两部分只是会根据数据访问方式有所变化,

Spring事务的五种实现方式

前段时间对spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的. 总结如下: Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSource.TransactionManager这两部分只是会根据数据访问方式有所变化,

C#_批量插入数据到Sqlserver中的四种方式

先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记录的ID的值然后再进行加1运算要少.而如果存在索引的情况下,每次插入记录都会进行索引重建,这是非常耗性能的.如果表中无可避免的存在索引,我们可以通过先删除索引,然后批量插入,最后再重建索引的方式来提高效率. create database CarSYS;    go    use CarSYS;  

Android——数据存储(四种方式之一)SharedPrefereces

Android--数据存储(四种方式) 1.SharedPrefereces   轻量级.XML  存储文件名,数据保存在data/data/basepackage/shared_prefs/myopt.xml中   实例-收藏-记住密码自动登录 //一种轻量级的数据存储方式//通过KEY 存入数据--putxxxx(key,value) 取出数据--getxxxx(key  default)   2.读写SD卡  SD的根目录  适用于数据流读写 3.SQLite  轻量级.dp文件多用于手机

JAVA中集合输出的四种方式

在JAVA中Collection输出有四种方式,分别如下: 一) Iterator输出. 该方式适用于Collection的所有子类. public class Hello { public static void main(String[] args) throws Exception { Set<Person> javaProgramers = new HashSet<Person>(); javaProgramers.add(new Person("aaron&qu

struts2访问国际化消息的四种方式

Struts2的国际化是建立在java国际化的基础之上的,因此具有强大的国际互能力.Struts2运行时自动检测当前的 Location,然后使用RsourceBundle加载对应的Locale资源文件.因为Struts2对java的国际化进行了封装,因此国际化起来更简单,用户一般提供不同国家的消息资源即可.在Struts2的国际化包含三个部分:前台的国际化,Action中的国际化,验证配置文件的国际化. 在Struts2中加载全局资源文件 国际化的前提是如何让Struts2能够加载到国际化消息

Android中多线程的使用四种方式最全总结

当我们启动一个App的时候,Android系统会启动一个Linux Process,该Process包含一个Thread,称为UI Thread或Main Thread.通常一个应用的所有组件都运行在这一个Process中,当然,你可以通过修改四大组件在Manifest.xml中的代码块(<activity><service><provider><receiver>)中的android:process属性指定其运行在不同的process中.当一个组件在启动的

jQuery绑定事件的四种方式:bind、live、delegate、on

1.jQuery操作DOM元素的绑定事件的四种方式 jQuery中提供了四种事件监听方式,分别是bind.live.delegate.on,对应的解除监听的函数分别是unbind.die.undelegate.off. 2.必备的基础知识: DOM树 示例,这是在browser环境下的一棵模拟DOM树: 我们的页面可以理解为一棵DOM树,当我们在叶子结点上做什么事情的时候(如click一个a元素),如果我们没有人为的设置stopPropagation(Moder Browser), cancel