上一篇文章总结了Spring事务管理的相关知识点。接下来写一个模拟银行转账的案例来实际操作一下。
一、转账环境搭建
- 创建数据库表
CREATE DATABASE spring_transation;
USE spring_transation;
CREATE TABLE account (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) NOT NULL,
money double DEFAULT NULL,
PRIMARY KEY (id)
)
- 插入初始数据
INSERT INTO account VALUES ('1','aaa',1000);
INSERT INTO account VALUES ('2','bbb',1000);
INSERT INTO account VALUES ('3','ccc',1000);
- 创建Spring项目
使用IDEA,用Maven来构建一个Spring项目。
参考链接:IDEA搭建Spring项目(Maven版)
pom.xml文件中引入所需要的依赖:
<dependencies>
<!--spring所需依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!--其他需要的包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!--mysql driver-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!--c3p0-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
我的项目目录结构如下:
- 定义接口方法
①新建业务层接口AccountService,定义转账方法
//转账业务接口
public interface AccountService {
public void transfer(String out, String in, Double money);
}
②业务层接口实现类
public class AccountServiceImpl implements AccountService{
@Override
public void transfer(String out, String in, Double money) {
}
}
③新建数据访问层接口AccountDao
//转账Dao层接口
public interface AccountDao {
public void outMoney(String out, Double money);
public void inMoney(String in, Double money);
}
④Dao接口实现类
Spring中提供了一个关于jdbc操作的模板类,只需让Dao实现类继承JdbcDaoSupport即可。
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String out, Double money) {
}
@Override
public void inMoney(String in, Double money) {
}
}
- 加载Bean配置
修改applicationContext.xml文件:
①引入数据库属性文件
<context:property-placeholder location="classpath:jdbc.properties"/>
②配置c3po连接池
<!-- 配置C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver_class}"/>
<property name="jdbcUrl" value="${jdbc.connection.url}"/>
<property name="user" value="${jdbc.connection.username}"/>
<property name="password" value="${jdbc.connection.password}"/>
</bean>
③配置Dao层类
<!--配置Dao的类-->
<bean id="accountDao" class="cn.lovebugs.spring.demo.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/><!--注入连接池,因为DaoImpl类中继承了jdbc模板类,所以这里只要注入连接池就可以获得jdbc模板-->
</bean>
④配置业务层类
<!--配置业务层类-->
<bean id="accountService" class="cn.lovebugs.spring.demo.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
- 完善接口方法
前面已经定义好了转账所需要的方法,也做好了先相关的配置及jdbc模板,接下来只需完善转账方法即可。
①完善业务层接口实现类
public class AccountServiceImpl implements AccountService{
//注入转账的Dao类,xml文件中的<property name="accountDao" ref="accountDao"/>
private AccountDao accountDao;
//设值注入
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
@Override
public void transfer(String out, String in, Double money) {
accountDao.outMoney(out,money);
accountDao.inMoney(in,money);
}
}
②完善Dao层实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String out, Double money) {
String sql = "update account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql,money,out);//jdbc模板类执行sql语句
}
@Override
public void inMoney(String in, Double money) {
String sql = "update account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql,money,in);
}
}
二、测试
上面已经搭建好了基本的转账环境,接下来进行测试。
这里额外引入了一个测试相关的jar包:spring-test-3.2.0.RELEASE.jar
- 新建测试类,方法如下:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class SpringTest {
@Resource(name = "accountService")
private AccountService accountService;//引入业务类
@Test
public void test(){
accountService.transfer("aaa","bbb",200d);
}
}
- 运行test()方法,查看数据库结果
转账成功。
三、无事务管理造成的问题
前面所搭建的转账案例是没有进行事务管理的情况下实现的,因此它存在很大地安全隐患。比如a要向b转账200元,当a的账户减少200元后,此时如果程序发生异常被终止,那么b的账户就无法增加200元,这样就造成了数据不一致的问题。
如下示例:
在AccountServiceImpl类的transfer()方法中加入一条异常语句
@Override
public void transfer(String out, String in, Double money) {
accountDao.outMoney(out,money);
int a = 1 / 0; //强制使程序发生异常
accountDao.inMoney(in,money);
}
此时再运行test()方法后查看数据库结果
结果显然发现a的账户减少了200元,但是b的账户并没有改变。
这就看出了不加事务管理所造成的后果。
下一篇文章将会写一下如何进行事务处理。
微信公众号【IT资源社】
本公众号致力于免费分享全网最优秀的视频资源,学习资料,面试经验等,前端,PHP,JAVA,算法,Python,大数据等等,你想要的这都有,还会分享优质博文,提高你的认知与思维
IT资源社-QQ交流群:625494093
要进微信交流群的话加微信:super1319164238
微信搜索公众号:IT资源社 或者扫描下方二维码直接关注,
原创文章,转载请注明出处
网友评论