事物管理主要解决一类问题,比如去银行转账,中间出了些故障,导致转账失败,您的钱转过去了,但是对方并没有收到。这样显然不行,所以事物管理就是让事物同时成功或者同时失败。
下面是一个小小的项目从0开始来引导大家说明一下,以eclipse为例。
1. 首先是新建一个dynamic web project:
2.配置相关的jar包 从spring官网弄出来的。此外还要从maven仓库中弄到的mysql连接的jar包。
还需要这几个自行下载吧。
将其导入build path
3.编写代码
AccoutnDAO接口:
package cn.muke.spring.demo1;
import org.springframework.stereotype.Repository;
/**
* @ClassName: AccountDAO
* @Description: TODO
* @author: Robert_Wang
* @date: 2018年8月14日 下午2:38:22
*/
public interface AccountDAO {
/**
* @param out 转出方
* @param money 金额
*/
public void outmoney(String out, Double money);
/**
* @Title: inmoney
* @Description: TODO
* @param in
* @param money void
* @author Robert_Wang
* @date 2018年8月14日下午2:38:32
*/
public void inmoney(String in, Double money);
}
对应的实现类:
package cn.muke.spring.demo1;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
/**
* @author asus
*
*/
/**
* @ClassName: AccountDAOImpl
* @Description: TODO
* @author: Robert_Wang
* @date: 2018年8月14日 下午2:39:06
*/
public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {
/* (non Javadoc)
* @Title: outmoney
* @Description: TODO
* @param out
* @param money
* @see cn.muke.spring.demo1.AccountDAO#outmoney(java.lang.String, java.lang.Double)
*/
@Override
public void outmoney(String out, Double money) {
// TODO Auto-generated method stub
String sql = "update account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql,money,out);
System.out.println("Transfer out money successfully");
}
/* (non Javadoc)
* @Title: inmoney
* @Description: TODO
* @param in
* @param money
* @see cn.muke.spring.demo1.AccountDAO#inmoney(java.lang.String, java.lang.Double)
*/
@Override
public void inmoney(String in, Double money) {
// TODO Auto-generated method stub
String sql = "update account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql,money,in);
System.out.println("Transfer in money successfully");
}
}
对应实现类:
package cn.muke.spring.demo1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
/**
* @ClassName: AccountServiceImpl
* @Description: TODO
* @author: Robert_Wang
* @date: 2018年8月14日 下午2:40:00
*/
public class AccountServiceImpl implements AccountService {
//xml文件中已经将其注入了
private AccountDAO accountDAO;
private TransactionTemplate transactionTemplate;
public void setAccountDAO(AccountDAO accountDAO) {
this.accountDAO = accountDAO;
}
//注入事物管理的模板
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
//此处应该用final, 因为该方法new了一个内部类
/* (non Javadoc)
* @Title: transfer
* @Description: TODO该方法即执行事物,要么全部成功,要么全部失败。
* @param out
* @param in
* @param money
* @see cn.muke.spring.demo1.AccountService#transfer(java.lang.String, java.lang.String, java.lang.Double)
*/
@Override
public void transfer(String out, String in, Double money) {
// TODO Auto-generated method stub
//执行事物的地方
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
// TODO Auto-generated method stub
accountDAO.outmoney(out, money);
// int i = 1/0;如果执行此句,则发生错误,该方法内部的所有执行都将会失败。
accountDAO.inmoney(in, money);
System.out.println("Transfer money successfully");
}
});
}
}
4.接下来,要在src下面建立一个jdbc.properties和log4j.proeprties。
这里由于隐私的原因,仅展示log4j的文件:
# Configure logging for testing: optionally with log file
log4j.rootLogger=WARN, stdout
# log4j.rootLogger=WARN, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
5.这就是学习spring的重点了。
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"
xmlns:aop="http://www.springframework.org/schema/aop"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置c3p0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置业务层-->
<bean id="accountService" class="cn.muke.spring.demo1.AccountServiceImpl" >
<property name="accountDAO" ref="accountDAO"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<!-- 配置DAO层-->
<bean id="accountDAO" class="cn.muke.spring.demo1.AccountDAOImpl">
<!-- 注入连接池-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事物管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 管理连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事物管理模板:简化[事物管理]的代码 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
</beans>
注意几点:
1)c3p0的连接池那里:properties的name不能变,都是固定的哈,详情可以点击上面的类进去看。
2)DAO里面的注入连接池的dataSource是父类的set方法,所以name也是固定的哈。
3)事物管理的模板的transactionManager同上。
6.最后就是测试了:
package cn.muke.spring.demo1;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
//加载核心配置文件
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class SpringDemo1Test {
//注入
@Resource(name="accountService")
private AccountService accountService;
@Test
public void testDemo1() {
System.out.println("start");
accountService.transfer("aaa", "bbb", 200d);
System.out.println("end");
}
}