© 版权声明:本文为博主原创文章,转载请注明出处
案例:利用Spring的编程式事务管理模拟转账过程
数据库准备
-- 创建表 CREATE TABLE `account`( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `money` DOUBLE DEFAULT 0, PRIMARY KEY (`id`) )ENGINE = INNODB DEFAULT CHARSET = UTF8; -- 初始化数据 INSERT INTO account (name, money) VALUES ('张三', 1000); INSERT INTO account (name, money) VALUES ('李四', 1000); INSERT INTO account (name, money) VALUES ('王五', 1000);
实例
1.项目结构
2.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.spring</groupId> <artifactId>SpringTransaction-001</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SpringTransaction-001 Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.verion>4.3.8.RELEASE</spring.verion> </properties> <dependencies> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.verion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.verion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.verion}</version> </dependency> <!-- spring-dao --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.verion}</version> </dependency> <!-- spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.verion}</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.42</version> </dependency> <!-- C3P0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> </dependencies> <build> <finalName>SpringTransaction-001</finalName> </build> </project>
3.jdbc.properties
jdbc.username=root jdbc.password=*** jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring_transaction?useSSL=true&characterEncoding=UTF-8
4.AccountDao.java
package org.spring.dao; /** * 转账DAO层接口 */ public interface AccountDao { /** * 转出 * * @param out * 转出账号 * @param money * 转出金额 */ void outMoney(String out, double money); /** * 转入 * * @param in * 转入账号 * @param money * 转入金额 */ void inMoney(String in, double money); }
5.AccountDaoImpl.java
package org.spring.dao.impl; import org.spring.dao.AccountDao; import org.springframework.jdbc.core.support.JdbcDaoSupport; /** * 转账DAO层实现类 * */ public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { // 转出 public void outMoney(String out, double money) { String sql = "update account set money = money - ? where name = ?"; this.getJdbcTemplate().update(sql, money, out); } // 转入 public void inMoney(String in, double money) { String sql = "update account set money = money + ? where name = ?"; this.getJdbcTemplate().update(sql, money, in); } }
6.AccountService.java
package org.spring.service; /** * 转账业务层接口 * */ public interface AccountService { /** * 转账 * * @param out * 转出账号 * @param in * 转入账号 * @param money * 转账金额 */ void transfer(String out, String in, Double money); }
7.AccountServiceImpl.java
package org.spring.service.impl; import org.spring.dao.AccountDao; import org.spring.service.AccountService;import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; /** * 转账业务层实现类 * */ public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } // 转账 public void transfer(final String out, final String in, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() {//使用事务进行管理 @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }); } }
8.applicationContext.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" 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.xsd"> <!-- 引入外部的属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置C3P0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 配置业务层类 --> <bean id="accountService" class ="org.spring.service.impl.AccountServiceImpl"> <!-- 注入DAO --> <property name="accountDao" ref="accountDao"/> <!-- 注入事务管理模板 --> <property name="transactionTemplate" ref="transactionTemplate"/> </bean> <!-- 配置DAO层类 --> <bean id="accountDao" class="org.spring.dao.impl.AccountDaoImpl"> <!-- 注入连接池 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入连接池 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <!-- 注入事务管理器 --> <property name="transactionManager" ref="transactionManager"/> </bean> </beans>
9.TestAccount.java
package org.spring.test; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.spring.service.AccountService; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestAccount { @Resource(name="accountService") private AccountService accountService; @Test public void testTransfer() { accountService.transfer("张三", "李四", 100d); } }
10.效果预览
10.1 正常执行
10.2 将AccountServiceImpl.java代码修改如下,执行
package org.spring.service.impl; import org.spring.dao.AccountDao; import org.spring.service.AccountService;import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; /** * 转账业务层实现类 * */ public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } // 转账 public void transfer(final String out, final String in, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() {//使用事务进行管理 @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.outMoney(out, money); int i = 1 / 0;//手动抛出异常 accountDao.inMoney(in, money); } }); } }