spring事务的实现(二):声明式事务
声明式事务步骤(以转账为例):
第一步:业务的层的哪些方法需要事务
package com.cc.service;
public interface IUserInfoService {
/*
* from:转出的账户 to:转入的账户 money:转的金额
*
*/
public void zz(int from, int to, int money) throws Exception;
}
第二步:在spring-datasource.xml中配置事务管理器 (注意:不同的orm框架 事务管理的方式不同)
<!--spring针对MyBaits的事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
第三步:在spring-datasource.xml中定义切面(注:切面=切点+通知)
<!-- 1、通知(增强+连接点) -->
<tx:advice id="txAdice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有以zz结束的方法 都会被匹配 -->
<tx:method name="*zz"/>
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 2、植入 -->
<aop:config>
<!-- 切点 -->
<aop:pointcut id="txPoint" expression="execution(* com.cc.service.impl.UserInfoServiceImpl2.*(..) )" />
<!-- 切面(advisor/aspect)=切点和通知 -->
<aop:advisor advice-ref="txAdice" pointcut-ref="txPoint"/>
</aop:config>
要注意的几个属性:
1.read-only:只读事务 在事务内不能修改数据
2.isolation=“DEFAULT”:指定事务隔离级别
3. rollback-for="" :指定方法产生哪种异常才进行事务的回滚
4. no-rollback-for="" :指定方法产生哪种异常不进行事务的回滚
5. timeout:事务的过期时间
6. propagation=“REQUIRED” 事务传播特性
第四步:在xml配置根据切点+增强 ,自动生成业务方法的代理对象
package com.cc.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import com.cc.mapper.UserInfoMapper;
import com.cc.model.UserInfo;
import com.cc.service.IUserInfoService;
//业务层
@Component
public class UserInfoServiceImpl2 implements IUserInfoService {
@Autowired
private UserInfoMapper userInfoMapper;
@Autowired
private TransactionTemplate transactionTemplate;
// @Autowired
// public UserInfoServiceImpl1(PlatformTransactionManager transactionManager) {
// this.transactionTemplate = new TransactionTemplate(transactionManager);
// }
/**
* 转账业务:旺财(from)转账给来福(to),转money钱
*
* 旺财(from) 更新操作 减money 来福 (to) 更新操作 加money money =200
*
*
* zz(1,2,300)
*/
@Override
public void zz(int from, int to, int money) throws Exception {
// 转账的操作
zzOptional(from, to, money);
}
private void zzOptional(int from, int to, int money) throws Exception {
// 一,==============旺财的钱减少300==============
// 1.1查询旺财有多少钱
UserInfo wc = userInfoMapper.selectByPrimaryKey(from);
System.out.println(wc);
// 1.2扣旺财有300
wc.setMoney(wc.getMoney() - money);
int result = userInfoMapper.updateByPrimaryKey(wc);
// ==============二,来福的钱增加300==============
// 1.1查询旺财有多少钱
UserInfo lf = userInfoMapper.selectByPrimaryKey(to);
System.out.println(lf);
// 1.2扣旺财有300
lf.setMoney(lf.getMoney() + money);
int result2 = userInfoMapper.updateByPrimaryKey(lf);
// ==============最后的结果==============
if (result > 0 && result2 > 0) {
System.out.println("转账成功!!");
} else {
// int a = 10/0;//产生一个异常
throw new Exception("转账失败");// 产生一个异常
}
}
}
第五步:编写单元测试方法
package com.cc.proxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.cc.mapper.UserInfoMapper;
import com.cc.service.IUserInfoService;
import com.cc.service.impl.UserInfoServiceImpl1;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-datasource.xml")
public class SpringTrasactionTest {
// 声明式事务的业务层类
@Autowired
@Qualifier("userInfoServiceImpl2")
private IUserInfoService iUserInfoService;
@Test
public void whenZz2Success() {
try {
iUserInfoService.zz(1, 2, 100);
} catch (Exception e) {
System.out.println("转账失败,回滚");
System.out.println(e.getMessage());
}
}
}