package com.hzyc.spring.jdbc.transaction.xml;
/**
* @author xuehj2016
* @Title: BookShopDao
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 20:32
*/
public interface BookShopDao {
/**
* 根据书号获取书的单价
*/
public int getBookPriceById(String id);
/**
* 更新书的库存,使书号对应的库存 - 1
*/
public void updateBookStock(String id);
/**
* 更新用户的账户余额 : 使 username 的 balance - price
*/
public void updateUserAccount(String username, int price);
}
package com.hzyc.spring.jdbc.transaction.xml;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author xuehj2016
* @Title: BookShopDaoImpl
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 20:39
*/
public class BookShopDaoImpl implements BookShopDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
* 根据书号获取书的单价
*
* @param id
*/
@Override
public int getBookPriceById(String id) {
String sql = "select price from book where id = ?";
return jdbcTemplate.queryForObject(sql, Integer.class, id);
}
/**
* 更新书的库存,使书号对应的库存 - 1
*
* @param id
*/
@Override
public void updateBookStock(String id) {
//检查书的库存是否足够,若不够,则抛出异常
String stockSql = "select stock from book_stock where id =?";
int stock = jdbcTemplate.queryForObject(stockSql, Integer.class, id);
if (stock == 0) {
throw new BookStockException("库存不足!");
}
String sql = "update book_stock set stock = stock - 1 where id =?";
jdbcTemplate.update(sql, id);
}
/**
* 更新用户的账户余额 : 使 username 的 balance - price
*
* @param username
* @param price
*/
@Override
public void updateUserAccount(String username, int price) {
//因为 MySQL 不支持检查约束
//验证用户的余额是否足够,若不够,则抛出异常
String balanceSql = "select balance from account where username =?";
int balance = jdbcTemplate.queryForObject(balanceSql, 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.hzyc.spring.jdbc.transaction.xml;
/**
* @author xuehj2016
* @Title: BookShopService
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 21:22
*/
public interface BookShopService {
public void purchase(String username, String id);
}
package com.hzyc.spring.jdbc.transaction.xml;
/**
* @author xuehj2016
* @Title: BookShopServiceImpl
* @ProjectName Spring-3
* @Description: TODO
* @date 2018/12/21 21:24
*/
public class BookShopServiceImpl implements BookShopService {
private BookShopDao bookShopDao;
public void setBookShopDao(BookShopDao bookShopDao) {
this.bookShopDao = bookShopDao;
}
@Override
public void purchase(String username, String id) {
//1.获取书的单价
int price = bookShopDao.getBookPriceById(id);
//2.更新书的库存
bookShopDao.updateBookStock(id);
//3.更新用户余额
bookShopDao.updateUserAccount(username, price);
}
}
package com.hzyc.spring.jdbc.transaction.xml;
/**
* @author xuehj2016
* @Title: BookStockException
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 21:10
*/
public class BookStockException extends RuntimeException {
public BookStockException() {
}
public BookStockException(String message) {
super(message);
}
public BookStockException(String message, Throwable cause) {
super(message, cause);
}
public BookStockException(Throwable cause) {
super(cause);
}
public BookStockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.hzyc.spring.jdbc.transaction.xml;
import java.util.List;
/**
* @author xuehj2016
* @Title: Cashier
* @ProjectName Spring-3
* @Description: TODO
* @date 2018/12/21 23:23
*/
public interface Cashier {
public void checkout(String username, List<String> ids);
}
package com.hzyc.spring.jdbc.transaction.xml;
import java.util.List;
/**
* @author xuehj2016
* @Title: CashierImpl
* @ProjectName Spring-3
* @Description: TODO
* @date 2018/12/21 23:24
*/
public class CashierImpl implements Cashier {
private BookShopService bookShopService;
public void setBookShopService(BookShopService bookShopService) {
this.bookShopService = bookShopService;
}
/**
*
* @param username
* @param ids
*/
@Override
public void checkout(String username, List<String> ids) {
for (String id : ids) {
bookShopService.purchase(username, id);
}
}
}
package com.hzyc.spring.jdbc.transaction.xml;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Arrays;
/**
* @author xuehj2016
* @Title: SpringTransactionTest
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 20:52
*/
public class SpringTransactionTest {
private BookShopDao bookShopDao;
private BookShopService bookShopService;
private Cashier cashier;
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-context-tx-xml.xml");
bookShopDao = (BookShopDao) applicationContext.getBean("bookShopDao2");
bookShopService = (BookShopService) applicationContext.getBean("bookShopService2");
cashier = (Cashier) applicationContext.getBean("cashier2");
}
@Test
public void testBookShopGetBookPriceById() {
System.out.println(bookShopDao.getBookPriceById("1001"));
}
@Test
public void testBookShopUpdateBookStock() {
bookShopDao.updateBookStock("1001");
}
@Test
public void testBookShopUpdateUserAccount() {
bookShopDao.updateUserAccount("xuehj", 50);
}
@Test
public void testBookShopService() {
bookShopService.purchase("xuehj", "1001");
}
@Test
public void testTransactionalPropagation() {
cashier.checkout("xuehj", Arrays.asList("1001", "1002"));
}
}
package com.hzyc.spring.jdbc.transaction.xml;
/**
* @author xuehj2016
* @Title: UserAccountException
* @ProjectName Spring
* @Description: TODO
* @date 2018/12/21 21:16
*/
public class UserAccountException extends RuntimeException {
public UserAccountException() {
}
public UserAccountException(String message) {
super(message);
}
public UserAccountException(String message, Throwable cause) {
super(message, cause);
}
public UserAccountException(Throwable cause) {
super(cause);
}
public UserAccountException(String message, Throwable cause, boolean enableSuppression, boolean
writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
application-context-tx-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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.hzyc.spring"/>
<!--导入资源文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置 c3p0 数据源-->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
<!--配置 Spring 的 Jdbc Template-->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置bean-->
<bean id="bookShopDao2" class="com.hzyc.spring.jdbc.transaction.xml.BookShopDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="bookShopService2" class="com.hzyc.spring.jdbc.transaction.xml.BookShopServiceImpl">
<property name="bookShopDao" ref="bookShopDao2"/>
</bean>
<bean id="cashier2" class="com.hzyc.spring.jdbc.transaction.xml.CashierImpl">
<property name="bookShopService" ref="bookShopService2"/>
</bean>
<!--1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3.配置事务属性-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--3.配置事务切入点,以及把事务切入点和事务属性关联起来-->
<aop:config>
<aop:pointcut id="txPointCut"
expression="execution(* com.hzyc.spring.jdbc.transaction.xml.BookShopService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
把上述文件移动包
2、目录结构
Spring
|——src
|——|——com.hzyc.spring.jdbc.transaction.xml
|——|——|——bookshopDao.java
|——|——|——bookshopDaoImpl.java
|——|——|——bookstockException.java
|——|——|——SpringTransactionTest.java
|——|——com.hzyc.spring.jdbc.transaction.xml.service
|——|——|——BookShopService.java
|——|——|——Cashier.java
|——|——com.hzyc.spring.jdbc.transaction.xml.service.impl
|——|——|——BookShopServiceImpl.java
|——|——|——CashierImpl.java
|——|——application-context.xml
|——|——db.properties
变得文件只是application-context-tx-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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.hzyc.spring"/>
<!--导入资源文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置 c3p0 数据源-->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
<!--配置 Spring 的 Jdbc Template-->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置bean-->
<bean id="bookShopDao2" class="com.hzyc.spring.jdbc.transaction.xml.BookShopDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="bookShopService2" class="com.hzyc.spring.jdbc.transaction.xml.service.impl.BookShopServiceImpl">
<property name="bookShopDao" ref="bookShopDao2"/>
</bean>
<bean id="cashier2" class="com.hzyc.spring.jdbc.transaction.xml.service.impl.CashierImpl">
<property name="bookShopService" ref="bookShopService2"/>
</bean>
<!--1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3.配置事务属性-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--根据方法名配置事务的属性-->
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="purchase" propagation="REQUIRES_NEW"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--3.配置事务切入点,以及把事务切入点和事务属性关联起来-->
<aop:config>
<aop:pointcut id="txPointCut"
expression="execution(* com.hzyc.spring.jdbc.transaction.xml.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>