使用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>

目录结构

相关推荐
爱由芯生3 分钟前
JFinal加密你值得学习
java
MacroZheng6 分钟前
横空出世!一款开源的数据同步工具,稳定又高效,好用到爆!
java·后端·mysql
你想考研啊14 分钟前
部署tomcat应用时注意事项
java·tomcat
喵手20 分钟前
Java中的垃圾回收机制(GC),你知道如何优化吗?
java·后端·java ee
大新屋21 分钟前
MongoDB 分片集群复制数据库副本
数据库·mongodb
ldrtech23 分钟前
雪花id的生成与应用问题处理
java
努力的小郑24 分钟前
放弃使用 Redis 事务!这才是它正确的打开方式!
数据库·redis
灵魂猎手27 分钟前
7. MyBatis 的 ResultSetHandler(一)
java·后端·源码
AAA修煤气灶刘哥30 分钟前
手把手教你全流程项目部署:从 Jenkins 到 Nginx 的项目实战手册
java·运维·后端