Spring 框架实现账户转账功能全解析
一、引言
在企业级应用开发中,事务管理是非常重要的一部分。例如在银行转账业务中,需要保证付款和收款操作要么同时成功,要么同时失败,以确保数据的一致性和完整性。Spring 框架为我们提供了强大的事务管理功能,本文将详细介绍如何使用 Spring 框架实现一个简单的账户转账功能,并对相关代码进行深入解析。
二、项目整体架构
本项目主要包含服务层、数据访问层、配置类和测试类,通过 Spring 框架的依赖注入和事务管理功能,实现账户转账的业务逻辑。下面是项目中各个文件的主要作用:
- AccountService.java:定义转账服务的接口。
- AccountDao.java 和 AccountDaoImpl.java:数据访问层,负责数据库的增删改查操作。
- AccountServiceImpl.java:实现转账服务的具体逻辑。
- TransactionConfig.java 和 AppConfig.java:配置类,用于配置数据源、事务管理器等。
- Test.java:测试类,用于测试转账功能。
三、代码详细解析
1. 服务层接口 AccountService.java
java
package com.qcby.service;public interface AccountService {/*** 转账的方式* @param out 付款人* @param in 收款人* @param money 金额*/public void pay(String out,String in, double money);
}
该接口定义了一个 pay
方法,用于实现转账功能,接收付款人、收款人姓名和转账金额作为参数。
2. 数据访问层 AccountDao.java
和 AccountDaoImpl.java
AccountDao.java
java
package com.qcby.dao;public interface AccountDao {void outMoney(String out,double money);void inMoney(String in,double money);
}
定义了两个方法,outMoney
用于从付款人账户扣除金额,inMoney
用于向收款人账户增加金额。
AccountDaoImpl.java
java
package com.qcby.dao.Impl;import com.qcby.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;@Component
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void outMoney(String out,double money) {jdbcTemplate.update("update account set money=money-? where name=?",money,out);}@Overridepublic void inMoney(String in,double money) {jdbcTemplate.update("update account set money=money+? where name=?",money,in);}
}
使用 Spring 的 JdbcTemplate
来执行 SQL 语句,实现了 AccountDao
接口中的两个方法。
3. 服务层实现类 AccountServiceImpl.java
java
package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)@Overridepublic void pay(String out,String in, double money) {accountDao.outMoney(out,money);accountDao.inMoney(in,money);}
}
使用 @Service
注解将该类标记为服务层组件,使用 @Transactional
注解开启事务管理,保证 pay
方法中的 outMoney
和 inMoney
操作要么同时成功,要么同时失败。
4. 配置类 TransactionConfig.java 和 AppConfig.java
TransactionConfig.java
java
package com.qcby.Utils;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;import javax.sql.DataSource;@Configuration
@EnableTransactionManagement//启动注解驱动的事务管理
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
配置事务管理器,使用 @EnableTransactionManagement
注解开启注解驱动的事务管理。
AppConfig.java
package com.qcby.Utils;import com.qcby.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration
@PropertySource("classpath:jdbc.properties")
@Import({TransactionConfig.class})//导入事务配置
@EnableAspectJAutoProxy(proxyTargetClass=true)
@EnableTransactionManagement
public class AppConfig {@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource) {return new JdbcTemplate(dataSource);}@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}}
配置数据源、JdbcTemplate
和事务管理器,使用 @PropertySource
注解加载数据库配置文件。
5. 测试类 Test.java
import com.qcby.Utils.AppConfig;
import com.qcby.Utils.UserProxy;
import com.qcby.entity.Account;
import com.qcby.service.AccountService;
import com.qcby.service.UserService;
import com.qcby.service.impl.UserServiceImpl;
import org.aspectj.lang.annotation.Around;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {AppConfig.class, UserProxy.class})
public class Test {@org.junit.Testpublic void test() {ApplicationContext context = new AnnotationConfigApplicationContext(UserProxy.class);UserService userService = (UserService) context.getBean("userserviceimpl");userService.save();}@org.junit.Testpublic void test2() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/spring_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");dataSource.setUsername("root");dataSource.setPassword("123456");JdbcTemplate template = new JdbcTemplate(dataSource);//完成數據增刪改查template.update("insert into account values (null,?,?)","熊er",2000);}@Autowiredprivate JdbcTemplate jdbcTemplate;@org.junit.Testpublic void test3() {jdbcTemplate.update("insert into account values (null,?,?) ","翠花",200000);}@org.junit.Testpublic void test4() {jdbcTemplate.update("update account set name=? where money=?",new Object[]{"光頭强",200000});}@org.junit.Testpublic void test5() {List<Account> list = jdbcTemplate.query("select * from account",new BeanMapper());for (Account account : list) {System.out.println(account);}}@org.junit.Testpublic void Pay() {String out = "熊大";String in="熊er";double money=500;ApplicationContext context =new ClassPathXmlApplicationContext("Spring.xml");AccountService accountService = (AccountService) context.getBean("accountService");accountService.pay(out,in,money);}@org.junit.Testpublic void test6() {ApplicationContext context =new AnnotationConfigApplicationContext(UserProxy.class);AccountService accountService = (AccountService) context.getBean(AccountService.class);accountService.pay("熊大","熊er",100);}
}class BeanMapper implements RowMapper<Account>{/***是一行一行进行数据封装的*@paramresultSet*@parami*@return*@throwsSQLException*/@Overridepublic Account mapRow(ResultSet resultSet, int i)throwsSQLException{Account account=new Account();account.setId(resultSet.getInt("id"));account.setName(resultSet.getString("name"));account.setMoney(resultSet.getDouble("money"));return account;}}
四、总结
通过本文的介绍,我们了解了如何使用 Spring 框架实现一个简单的账户转账功能。主要使用了 Spring 的依赖注入、JdbcTemplate
和事务管理功能,保证了转账操作的原子性和数据的一致性。在实际开发中,我们可以根据具体需求对代码进行扩展和优化,例如添加更多的业务逻辑和异常处理。
希望本文对大家理解 Spring 框架的事务管理和数据库操作有所帮助。如果你有任何问题或建议,欢迎在评论区留言。