编程式事务
还是采用经典案例 银行转账 来构建代码,假设张三和李四账户都有1000元,现在张三向李四转账200元,观察spring是怎么管理事务的。
一、代码示例
① dao类:
/**
* 创建人:taofut
* 创建时间:2019-01-08 19:31
* 描述:
*/
public interface AccountDao {
/**
* @param out 转出账号
* @param money 转账金额
*/
public void outMoney(String out,Double money);
/**
* @param in 转入账号
* @param money 转账金额
*/
public void inMoney(String in,Double money);
}
② dao实现类:
/**
* 创建人:taofut
* 创建时间:2019-01-08 19:33
* 描述:
*/
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
/**
* @param out 转出账号
* @param money 转账金额
*/
public void outMoney(String out, Double money) {
String sql="update account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql,money,out);
}
/**
* @param in 转入账号
* @param money 转账金额
*/
public void inMoney(String in, Double money) {
String sql="update account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql,money,in);
}
}
③ service类:
/**
* 创建人:taofut
* 创建时间:2019-01-08 19:26
* 描述:转账业务接口
*/
public interface AccountService {
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transfer(String out,String in,Double money);
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transferException(String out,String in,Double money);
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transferTransaction(String out, String in, Double money);
}
④ service实现类:
/**
* 创建人:taofut
* 创建时间:2019-01-08 19:29
* 描述:
*/
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
/**注入事务管理的模板*/
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transfer(String out, String in, Double money) {
accountDao.outMoney(out,money);
accountDao.inMoney(in,money);
}
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transferException(String out, String in, Double money) {
accountDao.outMoney(out,money);
int i = 1 / 0;
accountDao.inMoney(in,money);
}
/**
* @param out 转出账号
* @param in 转入账号
* @param money 转账金额
*/
public void transferTransaction(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);
}
});
}
}
⑤ 配置文件applicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 数据库连接池 -->
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>
<!--配置业务层类-->
<bean id="accountService" class="com.ft.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
<!--注入事务管理模板-->
<property name="transactionTemplate" ref="transactionTemplate" />
</bean>
<!--配置dao层类-->
<bean id="accountDao" class="com.ft.demo1.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>
二、spring事务所需条件
① 资源文件里面得配置事务管理器和事务管理模板,事务配置模板引用事务管理器,然后service类再引用事务管理模板。
② service类哪个方法需要加事务,就将该方法里的内容写入到如下代码里面:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//在这里写事务相应的代码
...
}
});
三、代码测试结果
import com.ft.demo1.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* 创建人:taofut
* 创建时间:2019-01-08 20:29
* 描述:转账案例测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest1 {
@Resource(name = "accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transferTransaction("zhangsan","lisi",200d);
System.out.println("转账完成...");
}
}
没加事务:
public void transferTransaction(final String out, final String in, final Double money) {
accountDao.outMoney(out,money);
int i = 1 / 0;
accountDao.inMoney(in,money);
}
张三给李四转了200元,然后出现异常,没回滚。李四增加200元的操作没进行下去,最终导致张三转了200元,李四没收到钱。200元就这么消失了,这显然是不合理的。
加了事务:
public void transferTransaction(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);
}
});
}
张三给李四转了200元,然后出现异常,回滚了。最终张三200元没转出去,李四也没收到钱。
四、总结
编程式事务,从字面意思就能理解它是需要我们手动编写代码的,从“spring事务所需条件”我们知道,如果要给很多个service里的很多方法添加事务,那么资源文件里得配置很多service,并且每个service都得引用事务管理模板,每个方法里的内容也都要被事务配置模板方法给包裹进来,这样的做法耦合度太高,开发工作量也比较大,所以实际生活中用的很少。