Spring事务的实现方式

spring事务的实现方式

Spring事务有两种实现方式:编程式事务和声明式事务。编程式事务是指通过编码方式实现事务管理,缺点是与业务代码高度耦合,不同的业务代码需要编写不同的事务实现。声明式事务属于无侵入式,不会影响业务逻辑的实现。

1、编程式事务

Spring实现编程式事务,主要通过两个类:PlatformTransactionManager和TransactionTemplate(推荐使用)。

事务管理器配置:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="jdbcUrl" value="${db.jdbcUrl}" />
	<property name="user" value="${user}" />
	<property name="password" value="${password}" />
	<property name="driverClass" value="${db.driverClass}" />
	 <!--连接池中保留的最小连接数。 --> 
     <property name="minPoolSize"> 
         <value>5</value> 
     </property> 
     <!--连接池中保留的最大连接数。Default: 15 --> 
     <property name="maxPoolSize"> 
         <value>30</value> 
     </property> 
     <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> 
     <property name="initialPoolSize"> 
         <value>10</value> 
     </property> 
     <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> 
     <property name="maxIdleTime"> 
         <value>60</value> 
     </property> 
     <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> 
     <property name="acquireIncrement"> 
         <value>5</value> 
     </property> 
     <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。  如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --> 
     <property name="maxStatements"> 
         <value>0</value> 
     </property> 
     <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> 
     <property name="idleConnectionTestPeriod"> 
         <value>60</value> 
     </property> 
     <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> 
     <property name="acquireRetryAttempts"> 
         <value>30</value> 
     </property> 
     <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> 
     <property name="breakAfterAcquireFailure"> 
         <value>true</value> 
     </property> 
     <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false --> 
     <property name="testConnectionOnCheckout"> 
         <value>false</value> 
     </property> 
</bean>
<!--DataSourceTransactionManager位于org.springframework.jdbc.datasource包下,数据源事务管理类,提供对单个javax.sql.DataSource数据源的事务管理,主要用于JDBC,Mybatis框架事务管理。 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>

1.1、使用PlatformTransactionManager

import java.util.Map;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-public.xml" })
public class test {
	@Resource
	private PlatformTransactionManager txManager;

	@Resource
	private  DataSource dataSource;

	private static JdbcTemplate jdbcTemplate;

	Logger logger=Logger.getLogger(test.class);

    private static final String INSERT_SQL = "insert into testtranstation(sd) values(?)";

    private static final String COUNT_SQL = "select count(*) from testtranstation";

	@Test
	public void testdelivery(){
		//定义事务隔离级别,传播行为,
	    DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
	    def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
	    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
	    //事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务
	    TransactionStatus status = txManager.getTransaction(def);  
	    jdbcTemplate = new JdbcTemplate(dataSource);
	    int i = jdbcTemplate.queryForInt(COUNT_SQL);  
	    System.out.println("表中记录总数:"+i);
	    try {  
	        jdbcTemplate.update(INSERT_SQL, "1");  
	        txManager.commit(status);  //提交status中绑定的事务
	    } catch (RuntimeException e) {  
	        txManager.rollback(status);  //回滚
	    }  
	    i = jdbcTemplate.queryForInt(COUNT_SQL);  
	    System.out.println("表中记录总数:"+i);
	}
}

1.2、使用TransactionTemplate

使用TransactionTemplate,该类继承了接口DefaultTransactionDefinition,用于简化事务管理,事务管理由模板类定义,主要是通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动实现事务管理。

TransactionTemplate模板类使用的回调接口:

TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;

TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。

@Test
public void testTransactionTemplate(){
	jdbcTemplate = new JdbcTemplate(dataSource);
    int i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中记录总数:"+i);
	//构造函数初始化TransactionTemplate
	TransactionTemplate template = new TransactionTemplate(txManager);
	template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
	//重写execute方法实现事务管理
	template.execute(new TransactionCallbackWithoutResult() {
		@Override
		protected void doInTransactionWithoutResult(TransactionStatus status) {
			jdbcTemplate.update(INSERT_SQL, "饿死");   //字段sd为int型,所以插入肯定失败报异常,自动回滚,代表TransactionTemplate自动管理事务
		}}
	);
	i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中记录总数:"+i);
}

2、声明式事务

声明式事务实现方式主要有五种:

1、基于 TransactionProxyFactoryBean的声明式事务管理-每个Bean都有一个代理类

2、基于 TransactionProxyFactoryBean的声明式事务管理-所有Bean共享一个代理类

3、通过TransactionInterceptor拦截器实现

4、通过@Transactional实现

5、通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现

下面以“用户购买股票”为例来讲解声明式事务。

新建用户对象、股票对象、以及dao、service层。

/**账户对象*/
public class Account {
	private int accountid;
	private String name;
	private String balance;
	//省略了get、set方法
}
/**股票对象*/
public class Stock {
	private int stockid;
	private String name;
	private Integer count;
	public Stock() {
		super();
	}
	public Stock(int stockid, String name, Integer count) {
		super();
		this.stockid = stockid;
		this.name = name;
		this.count = count;
	}
    //省略了get、set方法
}

/**用户DAO*/
public interface AccountDao {
void addAccount(String name,double money);
void updateAccount(String name,double money,boolean isbuy);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
	@Override
	public void addAccount(String name, double money) {
		String sql = "insert into account(name,balance) values(?,?);";
		this.getJdbcTemplate().update(sql,name,money);
		
	}
	@Override
	public void updateAccount(String name, double money, boolean isbuy) {
		String sql = "update account set balance=balance+? where name=?";
		if(isbuy)
			sql = "update account set balance=balance-? where name=?";
		this.getJdbcTemplate().update(sql, money,name);
	}
}
/**股票DAO*/
public interface StockDao {
void addStock(String sname,int count);
void updateStock(String sname,int count,boolean isbuy);
}
public class StockDaoImpl extends JdbcDaoSupport implements StockDao {
	@Override
	public void addStock(String sname, int count) {
		String sql = "insert into stock(name,count) values(?,?)";
		this.getJdbcTemplate().update(sql,sname,count);
	}
	@Override
	public void updateStock(String sname, int count, boolean isbuy) {
		String sql = "update stock set count = count-? where name = ?";
		if(isbuy)
			sql = "update stock set count = count+? where name = ?";
		this.getJdbcTemplate().update(sql, count,sname);
	}
}

/**购买股票Service接口*/
public interface BuyStockService {
	public void addAccount(String accountname, double money);
	public void addStock(String stockname, int amount);
	public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException;
}

/**service接口实现类*/
public class BuyStockServiceImpl implements BuyStockService{
	private AccountDao accountDao;

	private StockDao stockDao;

	@Override
	public void addAccount(String accountname, double money) {
		accountDao.addAccount(accountname,money);
	}

	@Override
	public void addStock(String stockname, int amount) {
		stockDao.addStock(stockname,amount);
	}

	@Override
	public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
		boolean isBuy = true;
        //修改用户的金额,用户花钱买股票之后,金额就会减少
		accountDao.updateAccount(accountname, money, isBuy);
        //修改用户持有的股票数量,用户购买股票之后,持股数量增加
        stockDao.updateStock(stockname, amount, isBuy);
        //这里抛出异常纯粹是为了模拟事务回滚,没有任何实际意义
		if(isBuy==true){
			throw new BuyStockException("购买股票发生异常");
		}
	}
}
/**自定义异常*/
public class BuyStockException extends Exception {
	public BuyStockException() {
		super();
	}

	public BuyStockException(String message) {
		super(message);
	}
}

2.1、基于TransactionProxyFactoryBean的声明式事务管理

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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-aop-4.2.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>
		 <property name="jdbcUrl"  value="${jdbc.url}"></property>
         <property name="user"  value="${jdbc.username}"></property>
         <property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 事务管理器。Spring 提供了多种事务管理器,如:DataSourceTransactionManager、JpaTransactionManager、HibernateTransactionManager 等,需要根据具体的数据源类型进行选择和配置。 -->
	<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.
DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="accountDao" class="transaction.test2.dao.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="stockDao" class="transaction.test2.dao.StockDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="buyStockService" class="transaction.test2.service.BuyStockServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
		<property name="stockDao" ref="stockDao"></property>
	</bean>

	<!-- 事务代理工厂 -->
	<!-- 生成事务代理对象 -->
<bean id="buyStockServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="myTracnsactionManager"></property>
		<!-- 每个Bean都有一个代理类 -->
		<property name="target" ref="buyStockService"></property>
		<property name="transactionAttributes">
			<props>
				<!--  key 是方法   
					ISOLATION_DEFAULT  事务的隔离级别
					PROPAGATION_REQUIRED  传播行为
				-->
				<prop key="add*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
				<!--  -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
		    	<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED, -BuyStockException</prop>
			</props>
		</property>
	</bean>
</beans>

如果有AccountService类,也想对其创建一个代理对象,类似于BuyStockServiceImpl 对应的代理对象id=" buyStockServiceProxy ",创建一个与AccountService类对应的代理对象id="accountServiceProxy"。这就会导致spring配置文件中充斥着大量的重复代码(上面生成事务代理对象的代码)。

有一种比较简单的方式是所有Bean共享一个代理基类。将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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-aop-4.2.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>
		 <property name="jdbcUrl"  value="${jdbc.url}"></property>
         <property name="user"  value="${jdbc.username}"></property>
         <property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 事务管理器。Spring 提供了多种事务管理器,如:DataSourceTransactionManager、JpaTransactionManager、HibernateTransactionManager 等,需要根据具体的数据源类型进行选择和配置。 -->
	<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.
DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="accountDao" class="transaction.test2.dao.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="stockDao" class="transaction.test2.dao.StockDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="buyStockService" class="transaction.test2.service.BuyStockServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
		<property name="stockDao" ref="stockDao"></property>
	</bean>

	<!-- 事务代理工厂 -->
	<!-- 生成事务代理对象 -->
    <bean id="baseTransactionProxy"             
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="myTracnsactionManager"></property>
		<property name="transactionAttributes">
			<props>
				<!--  key 是方法   
					ISOLATION_DEFAULT  事务的隔离级别
					PROPAGATION_REQUIRED  传播行为
				-->
				<prop key="add*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
				<!--  -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
		    	     <prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED, -BuyStockException</prop>
			</props>
		</property>
	</bean>
	<!-- 所有Bean共享一个代理基类 -->
    <bean id="buyStockServiceProxy" parent="baseTransactionProxy" >  
         <property name="target" ref=" buyStockService" />   
    </bean>
    <bean id="accountServiceProxy" parent="baseTransactionProxy" >  
         <property name="target" ref=" accountService" />   
    </bean>

</beans>

测试类:

public static void main(String[] args) {
	String resouce = "transaction/test2/applicationContext.xml";
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
	BuyStockService buyStockService =  (BuyStockService) applicationContext.getBean("serviceProxy");
	try {
		buyStockService.buyStock("老王", 1000, "贵州茅台", 100);
	} catch (BuyStockException e) {
		e.printStackTrace();
	}
}

2.2、通过TransactionInterceptor拦截器实现

在上面代码的基础上修改,其他类不做改变,只修改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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-aop-4.2.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>
		 <property name="jdbcUrl"  value="${jdbc.url}"></property>
         <property name="user"  value="${jdbc.username}"></property>
         <property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 事务管理器。Spring 提供了多种事务管理器,如:DataSourceTransactionManager、JpaTransactionManager、HibernateTransactionManager 等,需要根据具体的数据源类型进行选择和配置。 -->
	<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.
DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="accountDao" class="transaction.test2.dao.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="stockDao" class="transaction.test2.dao.StockDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="buyStockService" class="transaction.test2.service.BuyStockServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
		<property name="stockDao" ref="stockDao"></property>
	</bean>
	
	<!-- 配置拦截器 -->
	<bean id="txInterceptor"  
        class="org.springframework.transaction.interceptor.TransactionInterceptor">  
        <property name="transactionManager" ref="myTracnsactionManager" />  
        <!-- 配置事务属性 -->
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>  
            </props>  
        </property>  
    </bean>
       
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
        <property name="beanNames">  
            <list>
				<value>buyStockService</value>
				<value>accountService</value>
				<!-- 对所有后缀为Service的bean都使用 txInterceptor -->
                <!-- <value>*Service</value> -->
            </list>  
        </property>  
        <property name="interceptorNames">  
            <list>  
                <value>txInterceptor</value>  
            </list>  
        </property>  
    </bean>
</beans>

2.3、通过@Transactional实现

在上面代码的基础上修改,其他类不做改变,只改变购买股票接口实现类和配置文件。

public class BuyStockServiceImpl implements BuyStockService{
	private AccountDao accountDao;
	private StockDao stockDao;
	
	@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
	@Override
	public void addAccount(String accountname, double money) {
		accountDao.addAccount(accountname,money);
	}

	@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
	@Override
	public void addStock(String stockname, int amount) {
		stockDao.addStock(stockname,amount);
	}
	         
    @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=BuyStockException.class)
	@Override
	public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
		boolean isBuy = true;
		accountDao.updateAccount(accountname, money, isBuy);
        stockDao.updateStock(stockname, amount, isBuy);
		if(isBuy==true){
			throw new BuyStockException("购买股票发生异常");
		}
	}
}

配置文件:

<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  >
	<property name="driverClass" value="${jdbc.driverClass}"></property>
	<property name="jdbcUrl"  value="${jdbc.url}"></property>
    <property name="user"  value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

<bean id="accountDao" class="transaction.test3.dao.AccountDaoImpl">
	<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="stockDao" class="transaction.test3.dao.StockDaoImpl">
	<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="buyStockService" class="transaction.test3.service.BuyStockServiceImpl">
	<property name="accountDao" ref="accountDao"></property>
	<property name="stockDao" ref="stockDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="myTracnsactionManager"/>

2.4、基于Aspectj AOP配置事务

通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现声明式事务。

同样的,只需修改service接口实现类和配置文件。

public class BuyStockServiceImpl implements BuyStockService{
	private AccountDao accountDao;
	private StockDao stockDao;
	@Override
	public void addAccount(String accountname, double money) {
		accountDao.addAccount(accountname,money);
	}
	@Override
	public void addStock(String stockname, int amount) {
		stockDao.addStock(stockname,amount);
	}
	@Override
	public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
		boolean isBuy = true;
		accountDao.updateAccount(accountname, money, isBuy);
stockDao.updateStock(stockname, amount, isBuy);
		if(isBuy==true){
			throw new BuyStockException("购买股票发生异常");
		}
	}
}

配置文件:

<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  >
	<property name="driverClass" value="${jdbc.driverClass}"></property>
	<property name="jdbcUrl"  value="${jdbc.url}"></property>
    <property name="user"  value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

<bean id="accountDao" class="transaction.test4.dao.AccountDaoImpl">
	<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="stockDao" class="transaction.test4.dao.StockDaoImpl">
	<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="buyStockService" class="transaction.test4.service.BuyStockServiceImpl">
	<property name="accountDao" ref="accountDao"></property>
	<property name="stockDao" ref="stockDao"></property>
</bean>
<!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
	<tx:attributes>
		<!-- 为连接点指定事务属性 -->
		<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
		<tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/>
	</tx:attributes>
</tx:advice>

<aop:config>
	<!-- 切入点配置 -->
	<aop:pointcut expression="execution(* *..service.*.*(..))" id="point"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值