spring-基于注解和配置文件配置事务-2

2.完全基于配置文件开启事务

项目结构:

ServiceImpl:

package com.cwh.spring.transaction.xml.service.impl;

import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.cwh.spring.transaction.xml.BookShopDao;
import com.cwh.spring.transaction.xml.service.BookShopService;

public class BookShopServiceImpl implements BookShopService {

    private BookShopDao bookShopDao;
    
    public void setBookShopDao(BookShopDao bookShopDao) {
		this.bookShopDao = bookShopDao;
	}

    [@Override](https://my.oschina.net/u/1162528)
    public void purchase(String username, String isbn) {

        //1. 获取单价
        int price = bookShopDao.findBookPriceByIsbn(isbn);

        //2. 更新库存(2.1如果不加事务管理,可能这一步没报错,下一步报错。于是
        //这一步执行了,改变了库存,但是没有扣除余额,数据就会不一致,没有保持完整性
        //          2.2如果这一步报错抛出异常,下一步将不会执行,数据完整性得以保存
        //      2.3如果异常被捕获【try-cath】,程序将会继续往下执行,事务不会回滚)

        bookShopDao.updateBookStock(isbn);

        //3. 更新用户帐户余额
        bookShopDao.updateUserAccount(username, price);
    }
}

加了事务的方法里面再调用事务方法(测试事务的传播行为):

package com.cwh.spring.transaction.xml.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cwh.spring.transaction.xml.service.BookShopService;
import com.cwh.spring.transaction.xml.service.Cashier;

public class CashierImpl implements Cashier {

	private BookShopService bookShopService;
	
	public void setBookShopService(BookShopService bookShopService) {
		this.bookShopService = bookShopService;
	}
	
	[@Override](https://my.oschina.net/u/1162528)
	public void checkout(String username, List<String> isbns) {
		for(String isbn: isbns){
			bookShopService.purchase(username, isbn);
		}
	}
}

DAO层,增删改查用JDBCTemplate实现:

package com.cwh.spring.transaction.xml;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

public class BookShopDaoImpl implements BookShopDao {

	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	[@Override](https://my.oschina.net/u/1162528)
	public int findBookPriceByIsbn(String isbn) {
		String sql = "SELECT price FROM book WHERE isbn = ?";
		return jdbcTemplate.queryForObject(sql, Integer.class, isbn);
	}

	[@Override](https://my.oschina.net/u/1162528)
	public void updateBookStock(String isbn) {
		//检查库存,不够就抛出异常
		String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
		int stock = jdbcTemplate.queryForObject(sql2, Integer.class, isbn);
		if(stock == 0){
			throw new BookStockException("库存不足");
		}
		
		String sql = "UPDATE book_stock SET stock = stock -1 WHERE isbn = ?";
		jdbcTemplate.update(sql, isbn);
	}

	[@Override](https://my.oschina.net/u/1162528)
	public void updateUserAccount(String username, int price) {
		//检查余额,不够就抛出异常
		String sql2 = "SELECT balance FROM account WHERE username = ?";
		int balance = jdbcTemplate.queryForObject(sql2, Integer.class, username);
		if(balance < price){
			throw new UserAccountException("余额不足");
		}
		
		String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
		jdbcTemplate.update(sql, price, username);
	}
}

异常类:

package com.cwh.spring.transaction.xml;

public class UserAccountException extends RuntimeException{

	private static final long serialVersionUID = 1L;

	public UserAccountException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public UserAccountException(String message, Throwable cause,
			boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public UserAccountException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public UserAccountException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public UserAccountException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}

	
	
}

配置文件applicationContext2-xml.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:tx="http://www.springframework.org/schema/tx"
	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-4.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<context:component-scan base-package="com.cwh.spring"></context:component-scan>

	<context:property-placeholder location="classpath:db.properties" />
	<!-- c3p0数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="driverClass" value="${driverClass}"></property>
		<property name="jdbcUrl" value="${jdbcUrl}"></property>
		
		<property name="maxPoolSize" value="${maxPoolSize}"></property>
		<property name="initialPoolSize" value="${initialPoolSize}"></property>
	</bean>
	
	<!-- Spring 的 jdbcTemplate 该对象-->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<bean id="bookShopService" class="com.cwh.spring.transaction.xml.service.impl.BookShopServiceImpl">
		<property name="bookShopDao" ref="bookShopDao"></property>
	</bean>
	
	<bean id="bookShopDao" class="com.cwh.spring.transaction.xml.BookShopDaoImpl">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	
	<bean id="cashier" class="com.cwh.spring.transaction.xml.service.impl.CashierImpl">
		<property name="bookShopService" ref="bookShopService"></property>
	</bean>
	
	<!-- 1.配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 2.配置事务属性 tx:method 针对方法配置事务*就是默认所有方法 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
		<!-- 根据方法名进行配置 ,方法名支持使用通配符,所以方法名都是手写的-->
			<tx:method name="purchase" propagation="REQUIRES_NEW"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="find*" read-only="true"/>
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 3.配置事务切入点以及把事务切入点和事务属性关联起来 -->
	<aop:config>
		<!-- <aop:pointcut expression="execution(* com.cwh.spring.transaction.xml.BookShopService.*(..))" -->
		 <aop:pointcut expression="execution(* com.cwh.spring.transaction.xml.service.impl.*.*(..))"
		id="txPointCut"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
	</aop:config>
</beans>

测试类:

package com.cwh.spring.transaction.xml;

import static org.junit.Assert.*;

import java.util.Arrays;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.cwh.spring.transaction.xml.service.BookShopService;
import com.cwh.spring.transaction.xml.service.Cashier;

public class SpringTransactionTest {

	private ApplicationContext ctx = null;
	private BookShopDao bookShopDao = null;
	private BookShopService bookShopService = null;
	private Cashier cashier = null;
	
	{
		ctx = new ClassPathXmlApplicationContext("applicationContext2-xml.xml");
		bookShopDao = ctx.getBean(BookShopDao.class);
		bookShopService = ctx.getBean(BookShopService.class);
		cashier = ctx.getBean(Cashier.class);
	}
	
	@Test
	public void testTransactionlPropagation(){
		cashier.checkout("AA", Arrays.asList("1001", "1002"));
	}
	
	@Test
	public void testBookShopService(){
		bookShopService.purchase("AA", "1001");
	}
}

数据库表:

转载于:https://my.oschina.net/u/3780366/blog/1836850

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值