Spring 框架实现账户转账功能(推荐)

 更新时间:2025年07月09日 09:58:27   作者:小白的代码日记  
通过本文的介绍,我们了解了如何使用Spring框架实现一个简单的账户转账功能,主要使用了 Spring 的依赖注入、和事务管理功能,保证了转账操作的原子性和数据的一致性,感兴趣的朋友跟随小编一起看看吧

一、引言

在企业级应用开发中,事务管理是非常重要的一部分。例如在银行转账业务中,需要保证付款和收款操作要么同时成功,要么同时失败,以确保数据的一致性和完整性。Spring 框架为我们提供了强大的事务管理功能,本文将详细介绍如何使用 Spring 框架实现一个简单的账户转账功能,并对相关代码进行深入解析。

二、项目整体架构

本项目主要包含服务层、数据访问层、配置类和测试类,通过 Spring 框架的依赖注入和事务管理功能,实现账户转账的业务逻辑。下面是项目中各个文件的主要作用:

  • AccountService.java:定义转账服务的接口。
  • AccountDao.java 和 AccountDaoImpl.java:数据访问层,负责数据库的增删改查操作。
  • AccountServiceImpl.java:实现转账服务的具体逻辑。
  • TransactionConfig.java 和 AppConfig.java:配置类,用于配置数据源、事务管理器等。
  • Test.java:测试类,用于测试转账功能。

三、代码详细解析

1. 服务层接口 AccountService.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

package com.qcby.dao;
public interface AccountDao {
    void outMoney(String out,double money);
    void inMoney(String in,double money);
}

定义了两个方法,outMoney 用于从付款人账户扣除金额,inMoney 用于向收款人账户增加金额。

AccountDaoImpl.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 {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void outMoney(String out,double money) {
        jdbcTemplate.update("update account set money=money-? where name=?",money,out);
    }
    @Override
    public void inMoney(String in,double money) {
        jdbcTemplate.update("update account set money=money+? where name=?",money,in);
    }
}

使用 Spring 的 JdbcTemplate 来执行 SQL 语句,实现了 AccountDao 接口中的两个方法。

3. 服务层实现类 AccountServiceImpl.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 {
    @Autowired
    private AccountDao accountDao;
    @Transactional(
            isolation = Isolation.DEFAULT,
            propagation = Propagation.REQUIRED
    )
    @Override
    public 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

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 {
    @Bean
    public 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;
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return  dataSource;
    }
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    @Bean
    public 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.Test
    public void test() {
        ApplicationContext context = new AnnotationConfigApplicationContext(UserProxy.class);
        UserService userService = (UserService) context.getBean("userserviceimpl");
        userService.save();
    }
    @org.junit.Test
    public 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);
    }
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @org.junit.Test
    public void test3() {
        jdbcTemplate.update("insert into account values (null,?,?) ","翠花",200000);
    }
    @org.junit.Test
    public void test4() {
        jdbcTemplate.update("update account set name=? where money=?",new Object[]{"光頭强",200000});
    }
    @org.junit.Test
    public void test5() {
        List<Account> list = jdbcTemplate.query("select * from account",new BeanMapper());
        for (Account account : list) {
            System.out.println(account);
        }
    }
    @org.junit.Test
    public 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.Test
    public 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
     */
    @Override
    public Account mapRow(ResultSet resultSet, int i)throws
    SQLException{
        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 框架的事务管理和数据库操作有所帮助。如果你有任何问题或建议,欢迎在评论区留言。

到此这篇关于Spring 框架实现账户转账功能全解析的文章就介绍到这了,更多相关Spring账户转账内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 从互联网上爬邮箱代码示例

    Java 从互联网上爬邮箱代码示例

    这篇文章介绍了Java 从互联网上爬邮箱的有关内容,主要是一个代码示例,小编觉得挺不错的,这里给大家分享下,需要的朋友可以了解。
    2017-10-10
  • 使用Spring Cloud Gateway实现动态路由的核心原理

    使用Spring Cloud Gateway实现动态路由的核心原理

    Spring Cloud Gateway 实现动态路由的核心是将路由规则从静态配置迁移到外部数据源,并通过事件机制实时刷新路由缓存,本文介绍使用Spring Cloud Gateway实现动态路由的核心原理,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • 基于Spring Boot 的小区人脸识别与出入记录管理系统功能

    基于Spring Boot 的小区人脸识别与出入记录管理系统功能

    文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型设计、接口开发与系统优化方案,为智慧社区提供高效安全管理工具,感兴趣的朋友跟随小编一起看看吧
    2025-08-08
  • SpringCloud通过MDC实现分布式链路追踪

    SpringCloud通过MDC实现分布式链路追踪

    在DDD领域驱动设计中,我们使用SpringCloud来去实现,但排查错误的时候,通常会想到Skywalking,但是引入一个新的服务,增加了系统消耗和管理学习成本,对于大型项目比较适合,但是小的项目显得太过臃肿了,所以本文介绍了SpringCloud通过MDC实现分布式链路追踪
    2024-11-11
  • java使用swt显示图片示例分享

    java使用swt显示图片示例分享

    这篇文章主要介绍了java使用swt显示图片示例,修改后就可变为图片浏览器,需要的朋友可以参考下
    2014-02-02
  • Java设计模式之装饰模式详解

    Java设计模式之装饰模式详解

    这篇文章主要介绍了Java设计模式中的装饰者模式,装饰者模式即Decorator Pattern,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,装饰模式又名包装模式。装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案
    2022-07-07
  • Java中&&与?表达式结合时出现的坑

    Java中&&与?表达式结合时出现的坑

    这篇文章主要给大家介绍了关于Java中&&与?表达式结合时出现的坑的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-02-02
  • Jenkins分布式集群配置方式

    Jenkins分布式集群配置方式

    这篇文章主要介绍了Jenkins分布式集群配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-07-07
  • 关于logback日志级别动态切换的四种方式

    关于logback日志级别动态切换的四种方式

    这篇文章主要介绍了关于logback日志级别动态切换的四种方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • nacos配置在代码中引用的方法讲解

    nacos配置在代码中引用的方法讲解

    这篇文章主要介绍了nacos配置在代码中如何引用,如果主配置中配置的内容和拓展配置的内容重复则按主配置的配置 ,如果拓展配置中的内容和另一个拓展配置中的内容重复,则按下标大的配置作为最终的配置,对nacos配置代码引用相关知识感兴趣朋友一起看看吧
    2022-12-12

最新评论