假设一个人去4s店买车,需要修改数据库中车辆库存和user的余额,选好车后发现没钱肯定不能提车即事务(如果有可以买车不付钱的地方请带上我)
xml文件配置
资源文件
user=root
password=****
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://127.0.0.1:3306/test
initPoolSize=5
maxPoolSize=10
<?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:jdbc="http://www.springframework.org/schema/jdbc" 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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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.spring.tx"></context:component-scan> <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 导入资源文件 src目录下的db.propertier文件 --> <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="jdbcUrl" value="${jdbcUrl}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="initialPoolSize" value="${initPoolSize}"></property> <property name="maxPoolSize" value="${maxPoolSize}"></property> </bean> <!-- 配置 Spirng 的 JdbcTemplate --> <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>
Dao类
package com.spring.tx; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; /** * * @version 创建时间:2017年8月15日 上午6:26:18 * 类说明 */ @Repository("carDao") public class CarDao { @Autowired private JdbcTemplate jdbcTemplate; public int findCarPriceByName(String name) { String sql = "select price from car where name = ?"; return jdbcTemplate.queryForObject(sql, Integer.class, name); } public void updataCarStock(String name) { String sql = "select stock from car where name = ?"; int stock = jdbcTemplate.queryForObject(sql,Integer.class, name); if(stock<=0) { throw new StockException("库存不足"); } sql = "update car set stock = stock-1 where name = ?"; jdbcTemplate.update(sql, name); } public void updataUserMoney(String name,int price) { String sql = "select money from user where name = ?"; int money = jdbcTemplate.queryForObject(sql,Integer.class,name); if(money<price) { throw new MoneyException("穷------"); //QAQ } sql = "update user set money = ? where name = ?"; money = money - price; jdbcTemplate.update(sql, money,name); } }
需要抛出的异常类
package com.spring.tx; /** * * @version 创建时间:2017年8月15日 上午6:44:14 * 类说明 */ public class StockException extends RuntimeException { //缺少库存 /** * */ private static final long serialVersionUID = 1L; public StockException() { super(); } public StockException(String massage) { // TODO Auto-generated constructor stub super(massage); } } package com.spring.tx; /** * * @version 创建时间:2017年8月15日 上午6:46:56 * 类说明 */ public class MoneyException extends RuntimeException{ /** * */ //缺钱 private static final long serialVersionUID = 1L; public MoneyException() { // TODO Auto-generated constructor stub super(); } public MoneyException(String massage) { // TODO Auto-generated constructor stub super(massage); } }
Service
package com.spring.tx; /** * * @version 创建时间:2017年8月15日 上午9:35:45 * 类说明 */ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service("carShopServlet") public class CarShopServlet { @Autowired private CarDao carDao; //添加事务注解 @Transactional public void purchase(String username, String carname) { int price = carDao.findCarPriceByName(carname); carDao.updataCarStock(carname); carDao.updataUserMoney(username, price); //要是没事务就可以买车不付钱了 } }
Test
package com.spring.tx; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.*; import java.sql.SQLException; import javax.sql.DataSource; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; /** * * @version 创建时间:2017年8月15日 上午7:00:01 * 类说明 */ public class Test { private ApplicationContext ctx = null; private CarShopServlet carShopServlet =null; { ctx = new ClassPathXmlApplicationContext("beans-tx.xml"); carShopServlet = (CarShopServlet) ctx.getBean("carShopServlet"); } @org.junit.Test public void testtx() { carShopServlet.purchase("关羽", "福特"); carShopServlet.purchase("关羽", "兰博基尼"); } @org.junit.Test public void testcon() throws SQLException {//测试是否连上数据库 // TODO Auto-generated constructor stub DataSource dataSource = (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource.getConnection()); /*JdbcTemplate jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate"); System.out.println(jdbcTemplate);*/ } }
运行前数据
运行后
买了福特 但是买不起兰博基尼
基于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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" 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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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.spring.tx.xml"></context:component-scan> <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 导入资源文件 --> <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="jdbcUrl" value="${jdbcUrl}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="initialPoolSize" value="${initPoolSize}"></property> <property name="maxPoolSize" value="${maxPoolSize}"></property> </bean> <!-- 配置 Spirng 的 JdbcTemplate --> <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"/>--> <!-- 配置事务属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 根据方法名指定事务的属性 --> <!-- 事务传播属性 默认为REQUIRES --> <tx:method name="purchase" propagation="REQUIRES_NEW"/> <tx:method name="get*" read-only="true"/> <tx:method name="find*" read-only="true"/> </tx:attributes> </tx:advice> <!-- 配置事务切入点, 以及把事务切入点和事务属性关联起来 --> <aop:config> <!-- 此包下的所有类的所有方法其实只有purchase一个方法 --> <aop:pointcut expression="execution(* com.spring.tx.xml.service.*.*(..))" id="txPointCut"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>