Implementing Transactional Fund Transfers in Spring
Data Model Configruation
Define the entity representing a financial account within the system.
package com.example.financial.model;
import java.io.Serializable;
public class BankAccount implements Serializable {
private Long accountId;
private String accountHolder;
private Double availableBalance;
public BankAccount() {
}
public BankAccount(Long accountId, String accountHolder, Double availableBalance) {
this.accountId = accountId;
this.accountHolder = accountHolder;
this.availableBalance = availableBalance;
}
// Getters and Setters
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountHolder() {
return accountHolder;
}
public void setAccountHolder(String accountHolder) {
this.accountHolder = accountHolder;
}
public Double getAvailableBalance() {
return availableBalance;
}
public void setAvailableBalance(Double availableBalance) {
this.availableBalance = availableBalance;
}
}
Data Access Layer (DAO)
Create an interface to hendle balence modifications via JDBC.
package com.example.financial.dao;
public interface AccountRepository {
int updateAccountBalance(Long accountId, Double amount);
}
Implement the repository using JdbcTemplate to execute the SQL update.
package com.example.financial.dao.impl;
import com.example.financial.dao.AccountRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class JdbcAccountRepository implements AccountRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int updateAccountBalance(Long accountId, Double amount) {
String sqlStatement = "UPDATE bank_accounts SET available_balance = available_balance + ? WHERE account_id = ?";
return jdbcTemplate.update(sqlStatement, amount, accountId);
}
}
Business Service Layer
Define the service contract for transferring funds between accounts.
package com.example.financial.service;
public interface TransferService {
boolean executeTransfer(Long sourceId, Long targetId, Double amount);
}
Implement the business logic to handle the debit and credit operations.
package com.example.financial.service.impl;
import com.example.financial.dao.AccountRepository;
import com.example.financial.service.TransferService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MoneyTransferService implements TransferService {
@Autowired
private AccountRepository accountRepository;
@Override
public boolean executeTransfer(Long sourceId, Long targetId, Double amount) {
// Debit the source account
int debitResult = accountRepository.updateAccountBalance(sourceId, -amount);
// Credit the target account
int creditResult = accountRepository.updateAccountBalance(targetId, amount);
return debitResult > 0 && creditResult > 0;
}
}
Integration Testing
Verify the functionality by initializing the Spring context and invoking the transfer method.
package com.example.financial.test;
import com.example.financial.service.TransferService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TransactionTestSuite {
@Test
public void testTransferExecution() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TransferService transferService = context.getBean(TransferService.class);
boolean status = transferService.executeTransfer(1L, 2L, 500.0);
System.out.println("Operation Status: " + status);
}
}