模拟银行事务 转账
需要:实现任意两个账号间转账操作
需求微缩:A账户捡钱,B账户加钱
分析:
- 数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)
- 业务层提供转账操作(transfer),调用减钱与加钱操作
- 提供2个账号和操作金额执行转账操作
- 基于Spring整合MyBatis环境搭建上述操作
结果分析:
- 程序正常执行时,账户金额A减B加,没问题
- 程序出现异常后,转账失败,但是异常之前操作成功,异常之后操作失败,整体业务失败。
以下是示例代码:
首先,我们定义一个 Account 实体类,用于表示用户账户信息。
public class Account {
private int id;
private String name;
private double balance;
// 省略 getter 和 setter 方法
}
接下来,定义一个 AccountDao 接口来操作 Account 实体类。
@Mapper
public interface AccountDao {
@Update("update account set balance = balance - #{amount} where name = #{accountName}")
void outMoney(@Param("accountName") String accountName, @Param("amount") double amount); // 减少账户余额
@Update("update account set balance = balance + #{amount} where name = #{accountName}")
void inMoney(@Param("accountName") String accountName, @Param("amount") double amount); // 增加账户余额
}
在JDBC配置类中配置事务管理信息
public class JdbcConfig {
@Value("${druid.driverName}")
private String driver;
@Value("${druid.url}")
private String url;
@Value("${druid.username}")
private String username;
@Value("${druid.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
//配置事务管理
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dtm = new DataSourceTransactionManager();
dtm.setDataSource(dataSource);
return dtm;
}
}
在配置类中开启事务
//设定当前文件为配置类
@Configuration
//开启事务
@EnableTransactionManagement
public class SpringConfig {
}
接下来,创建一个 AccountService 类,用于处理转账事务。需要注意的是,我们需要在 transfer() 方法中使用 Spring 的编程式事务管理机制来保证事务的原子性、一致性和隔离性。
在接口指明@Transactional,表示这个方法开启事务管理,方便管理。roolbackFor设置事务回滚事务异常,默认是RuntimeException运行时异常
public interface AcountService {
@Transactional(rollbackFor = Exception.class)
public void transfer(String out,String in,Double money) throws IOException;
}
@Service("AcountService")
public class AcountServiceImpl implements AcountService {
@Autowired
private AcountDao acountDao;
@Autowired
private LogService logService;
@Override
public void transfer(String out, String in, Double money) throws IOException {
try {
acountDao.outMoney(money,out);
if (true){
throw new IOException();
}
acountDao.inMoney(money,in);
}finally {
logService.insertLog(in,out,money);
}
}
}