sPRing声明式事务:
编写接口
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service("BookShopService")public class BookShopServiceImpl implements BookShopService{ @Autowired private BookShopDao bookShopDao; //添加事务注解 @Transactional @Override public void purchase(String username, String isbn) { //获取书的单价 int price=bookShopDao.findBookPriceByIsbn(isbn); //更新书的库存 bookShopDao.updateBookStock(isbn); //更新用户余额 bookShopDao.updateUserAccount(username, price); }}public interface BookShopDao { //根据书号查询价格 public int findBookPriceByIsbn(String isbn); //更新图书库存 public void updateBookStock(String isbn); //更新用户余额 public void updateUserAccount(String username,int price);}接口实现类
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;@Repository("BookShopDao")public class BookShopDaoImpl implements BookShopDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public int findBookPriceByIsbn(String isbn) { String sql="select price from book where isbn=?"; return jdbcTemplate.queryForObject(sql, Integer.class,isbn); } @Override public void updateBookStock(String isbn) { String sql2="select stock from book_stock where isbn=?"; Integer 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 public void updateUserAccount(String username, int price) { String sql2="select balance from account where username=?"; Integer 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); }}异常处理方法public class BookStockException extends RuntimeException{ /** * */ private static final long serialVersionUID = 1L; public BookStockException() { super(); // TODO Auto-generated constructor stub } public BookStockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public BookStockException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public BookStockException(String message) { super(message); // TODO Auto-generated constructor stub } public BookStockException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub }}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 }}配置文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <context:component-scan base-package="spring.transactionmanager"></context:component-scan> <!-- 加载配置文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="passWord" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="10" /> <property name="minIdle" value="5" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 启用事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/></beans>测试类import static org.junit.Assert.*;import org.junit.Test;import org.springframework.context.applicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringTransactionTest { ApplicationContext ctx=null; BookShopDao bookShopDao=null; BookShopService bookShopService=null; { ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); bookShopDao=ctx.getBean(BookShopDao.class); bookShopService=ctx.getBean(BookShopService.class); } @Test public void testBookShopService(){ bookShopService.purchase("AA", "1001"); } @Test public void testFindBookPriceByIsbn(){ System.out.println(bookShopDao.findBookPriceByIsbn("1001")); } @Test public void testUpdateBookStock(){ bookShopDao.updateBookStock("1001"); } @Test public void testUpdateUserAccount(){ bookShopDao.updateUserAccount("AA", 100); }}事务的传播行为:
当事务方法被另一个事务方法调用时,必须指明事务方法该如何传播
@Service("bookShopService")public class BookShopServiceImpl implements BookShopService{ @Autowired private BookShopDao bookShopDao; //添加事务注解 /* * 使用propagation制定事务的传播行为,即当前事务方法被另外一个事务方法调用时,如何使用事务,默认取值为REQUIRED,即使用调用方法的事务 * REQUIRES_NEW表示该方法必须启动一个新事务,并在一个自己的事务内运行,如果有事务在运行,就因该先挂起它 * */ @Transactional(propagation=Propagation.REQUIRES_NEW) @Override public void purchase(String username, String isbn) { //获取书的单价 int price=bookShopDao.findBookPriceByIsbn(isbn); //更新书的库存 bookShopDao.updateBookStock(isbn); //更新用户余额 bookShopDao.updateUserAccount(username, price); }}购买多本书:import java.util.List;public interface Casher { public void checkout(String username,List<String> isbns);}import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service("casher")public class CasherImpl implements Casher{ @Autowired private BookShopService bookShopService; @Transactional @Override public void checkout(String username, List<String> isbns) { for (String isbn : isbns) { bookShopService.purchase(username, isbn); } }}import static org.junit.Assert.*;import java.util.Arrays;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringTransactionTest { ApplicationContext ctx=null; BookShopDao bookShopDao=null; BookShopService bookShopService=null; private Casher casher=null; { ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); bookShopDao=ctx.getBean(BookShopDao.class); bookShopService=ctx.getBean(BookShopService.class); casher=(Casher) ctx.getBean("casher"); } @Test public void testTransactionPropagation(){ casher.checkout("AA", Arrays.asList("1001","1002")); }}
新闻热点
疑难解答