使用spring模拟转账,并实现异常事务回滚

1、数据库准备

使用配置类配置数据源、模板、事务回滚

java 复制代码
package cn.edu.aaa.utils;

import java.beans.PropertyVetoException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.mchange.v2.c3p0.ComboPooledDataSource;
@Configuration
@ComponentScan("cn.edu.aaa")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement //让事务注释@Transactional起作用
public class MyConfiguration {
	@Value("${driver}")
	private String driver;
	@Value("${url}")
	private String url;
	@Value("${user}")
	private String user;
	@Value("${password}")
	private String password;
	@Bean
//数据源
	public ComboPooledDataSource combopooledDataSource() throws PropertyVetoException {
		ComboPooledDataSource dataSource=new ComboPooledDataSource();
		dataSource.setJdbcUrl(url);
		dataSource.setDriverClass(driver);
		dataSource.setUser("root");
		dataSource.setPassword("root");
		return dataSource;
		
	}
//模板
	@Bean
	public JdbcTemplate jdbcTemplate(@Autowired DataSource dataSource) {
		JdbcTemplate jdbcTemplate=new JdbcTemplate();
		jdbcTemplate.setDataSource(dataSource);
		return jdbcTemplate;
		
	}
//事务处理
	
	  @Bean
	 public PlatformTransactionManager transactionManager(@Autowired DataSource dataSource) {
		  DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
		  transactionManager.setDataSource(dataSource);
		  return transactionManager;
	}
	 
}

2、创建DAO层

DAO层负责数据库操作。定义了金额操作的方法

(1)定义接口

java 复制代码
package cn.edu.aaa.dao;

public interface AccountDao {
	int addMoney(String aname,int money);
}

(2)接口实现类

java 复制代码
package cn.edu.aaa.dao.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import cn.edu.aaa.dao.AccountDao;
@Repository("AccountDao")//声明这个类是一个Spring管理的bean,并且bean的名称为"AccountDao"。这样,其他Spring组件可以通过"AccountDao"这个名称来引用这个bean。
@Scope("singleton")//声明这个bean的作用域为单例。这意味着在整个Spring容器中,这个bean只有一个实例。
public class AccountDaoImpl implements AccountDao{
	@Autowired //通过@Autowired注解,自动装配一个JdbcTemplate的实例
	private JdbcTemplate jdbcTemplate;
	public int addMoney(String aname, int money) {
		// TODO Auto-generated method stub
		int i=jdbcTemplate.update("update accounts set money=money+? where aname=?",money,aname);//执行一个SQL更新操作,返回更新的记录数
		return i;
	}

}

3、创建Service层

Service层是业务逻辑的核心。定义转账方法

(1)定义接口

java 复制代码
package cn.edu.aaa.biz;

public interface AccountBiz {
	boolean transfer(String aname1,String aname2,Integer money);
}

(2)接口实现类。步骤:

1)转账方金额变少

2)收款方金额变多

3)转账过程中发生异常(事务回滚),输出false,数据表数据不变

java 复制代码
package cn.edu.aaa.biz.impl;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import cn.edu.aaa.biz.AccountBiz;
import cn.edu.aaa.dao.AccountDao;

@Service("AccountBiz")
@Scope("singleton")
public class AccountBizImpl implements AccountBiz{
	@Autowired
	private AccountDao accountDao;
	@Transactional(isolation =Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
	public boolean transfer(String aname1, String aname2, Integer money) {
		// TODO Auto-generated method stub

		try {
			accountDao.addMoney(aname1, (-1)*money);
			//System.out.println(1/0);  //通过开放这句语句,来测试是否对异常处理
			accountDao.addMoney(aname2, money);
			return true;
		}catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//让事务只回滚
			return false;
		}
	}

}

4、测试转账功能

java 复制代码
package cn.edu.aaa.test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.experimental.theories.suppliers.TestedOn;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.edu.aaa.biz.AccountBiz;
import cn.edu.aaa.utils.MyConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes=MyConfiguration.class)//导入配置类

public class AccountBizTest {
	@Autowired

	private AccountBiz accountBiz;
	@Test
	public void test() {
		System.out.println(accountBiz.transfer("superman", "spiderman", 500));
		
	}


}

结果正常,输出true,数据表内容变化

结果异常,输出false,数据表内容不变

5、补充

pom.xml导入依赖

XML 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.edu.aaa</groupId>
  <artifactId>demo2</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.3.23</version>
  	</dependency>
  	
  	  <dependency>
  		<groupId>junit</groupId>
  		<artifactId>junit</artifactId>
  		<version>4.12</version>
  	</dependency> 
  	 
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-test</artifactId>
  		<version>5.3.23</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>org.aspectj</groupId>
  		<artifactId>aspectjweaver</artifactId>
  		<version>1.9.5</version>
  	</dependency>  
  	 
  	 <dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-jdbc</artifactId>
  		<version>5.3.23</version>
  	</dependency>
  	<dependency>
  		<groupId>com.mchange</groupId>
  		<artifactId>c3p0</artifactId>
  		<version>0.9.5.4</version>
  	</dependency>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>8.0.27</version>
  	</dependency>
  	<dependency>
  		<groupId>javax.annotation</groupId>
  		<artifactId>javax.annotation-api</artifactId>
  		<version>1.3.2</version>
  	</dependency>
  	
  	 
  	 
  </dependencies>
  
</project>

目录结构

相关推荐
Dovis(誓平步青云)1 小时前
从Redis指标采集到异常告警:redis_exporter + Prometheus 完整实战
服务器·数据库·人工智能·redis·架构·prometheus·vibe coding
tianyu2341 小时前
Java 正则表达式终极指南:从 Pattern 到 Matcher,从双重转义到性能优化,一篇全搞定
java·开发语言·正则表达式·group·find·pattern·matcher
Emily156853598703 小时前
Emerson 1C31129G03 Analog Input Module
java·开发语言·前端·plc·emerson·1c31129g03·input module
就叫_这个吧8 小时前
Java递归方法实现面包屑导航
java·开发语言
fīɡЙtīиɡ ℡8 小时前
AI 应用系统设计
java·开发语言·人工智能
城管不管8 小时前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
码匠许师傅8 小时前
【C++ 面试真题】26. 聊聊 C++ 的智能指针
java·c++·面试
倔强的石头1069 小时前
向量数据库从相似度检索走向融合数据底座
数据库
AI绘画哇哒哒9 小时前
【建议收藏!】35岁后端血泪忠告,这3类人别硬转Agent(过来人亲述)
java·人工智能·后端·ai·程序员·大模型·agent
最强小杰9 小时前
gpt-5.6-sol 频繁报 503 怎么办?区分容量熔断和限速 429 的排查方法 + 可复用 retry wrapper
java·人工智能·gpt·ai