You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data JPA查询报错:按账户与日期范围查询交易记录失败

银行应用交易记录查询问题及解决方案

问题描述

开发小型银行应用时,需根据用户账户、起始日期、结束日期查询交易记录,数据库transactionDate字段为Date类型。要求当用户提供的起始日期晚于结束日期(如2022-10-21作为起始日、2022-08-02作为结束日)时,仍能返回该日期区间内的所有交易。但当前自定义@Query查询抛出QueryCreationException错误。

报错信息

Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)! Reason: Validation failed for query for method public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.elijah.onlinebankingapp.repository.transaction.TransactionTypeRepository.findByBankAccountAndTransactionDate(com.elijah.onlinebankingapp.model.account.BankAccount,java.util.Date,java.util.Date)!

相关代码

TransactionType实体类

@Entity
@NoArgsConstructor
@Data
public class TransactionType {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Date transactionDate;
    private double amount;
    private double currentBalance;
    private String transactionType;
    private String description;
    private String depositorOrWithDrawalName;
    @ManyToOne
    @JoinColumn(name = "account_id")
    private BankAccount bankAccount;
}

BankAccount实体类

@Entity
@Data
@NoArgsConstructor
@Slf4j
public class BankAccount {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String accountType;
    private String accountStatus;
    private String accountNumber;
    private double currentBalance;
    private LocalDate createdDate;
    @OneToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

BankAccountStatement类

@Data
@NoArgsConstructor
public class BankAccountStatement {
    private double id;
    private String transactionDate;
    private String transactionType;
    private String description;
    private double amount;
    private double currentBalance;
    private String depositorOrWithDrawalName;
}

BankAccountStatementDto类

@Data
@NoArgsConstructor
public class BankAccountStatementDto {
    private Date startDate;
    private Date endDate;
}

Repository代码

@Repository
public interface TransactionTypeRepository extends JpaRepository<TransactionType,Long> {
    @Query("select t from TransactionType t where t.bankAccount =:bankAccount, t.transactionDate <=:startDate AND t.transactionDate >=:endDate")
    List<TransactionType> findByBankAccountAndTransactionDate(BankAccount bankAccount, @Param("startDate") Date startDate,@Param("endDate") Date endDate);
}

Service代码

@Service
public class TransactionTypeService {
    @Autowired
    private TransactionTypeRepository transactionTypeRepository;
    @Autowired
    private BankAccountService bankAccountService;
    public List<BankAccountStatement> getUserAccountStatement(BankAccountStatementDto bankAccountStatementDto, String accountNumber) throws DataNotFoundException {
        BankAccount bankAccount = bankAccountService.getAccountByAccountNumber(accountNumber);
        List<TransactionType> transactionTypeList = transactionTypeRepository.findByBankAccountAndTransactionDate(bankAccount,bankAccountStatementDto.getStartDate(),bankAccountStatementDto.getEndDate());
        List<BankAccountStatement> bankAccountStatementList = new ArrayList<>();
        BankAccountStatement bankAccountStatement = new BankAccountStatement();
        for (TransactionType transactionType: transactionTypeList){
            bankAccountStatement.setId(transactionType.getId());
            bankAccountStatement.setTransactionType(transactionType.getTransactionType());
            bankAccountStatement.setTransactionDate(transactionType.getTransactionDate().toString());
            bankAccountStatement.setDescription(transactionType.getDescription());
            bankAccountStatement.setDepositorOrWithDrawalName(transactionType.getDepositorOrWithDrawalName());
            bankAccountStatement.setCurrentBalance(transactionType.getCurrentBalance());
            bankAccountStatement.setAmount(transactionType.getAmount());
            bankAccountStatementList.add(bankAccountStatement);
        }
        return bankAccountStatementList;
    }
}

Controller代码

@RestController
public class TransactionController {
    @Autowired
    private TransactionTypeService transactionTypeService;
    @GetMapping("/account/statement/from/enteredDate")
    public ResponseEntity<List<BankAccountStatement>> getCustomerAccountStatement(@RequestBody BankAccountStatementDto bankAccountStatementDto,@RequestParam("accountNumber")String accountNumber) throws DataNotFoundException {
        return new ResponseEntity<>(transactionTypeService.getUserAccountStatement(bankAccountStatementDto,accountNumber),HttpStatus.OK);
    }
}

问题解决步骤

1. 修复Repository查询语法错误

原@Query中用逗号分隔where条件属于JPQL语法错误,需改为AND连接。同时为支持起始/结束日期任意顺序的查询,使用LEAST和GREATEST函数确保查询区间正确:

@Repository
public interface TransactionTypeRepository extends JpaRepository<TransactionType,Long> {
    @Query("select t from TransactionType t where t.bankAccount = :bankAccount AND t.transactionDate >= LEAST(:startDate, :endDate) AND t.transactionDate <= GREATEST(:startDate, :endDate)")
    List<TransactionType> findByBankAccountAndTransactionDateBetween(@Param("bankAccount") BankAccount bankAccount, @Param("startDate") Date startDate,@Param("endDate") Date endDate);
}

2. 修复Service中的对象复用问题

循环中重复使用同一个BankAccountStatement对象会导致列表所有元素引用同一实例,需将对象创建移至循环内部:

@Service
public class TransactionTypeService {
    @Autowired
    private TransactionTypeRepository transactionTypeRepository;
    @Autowired
    private BankAccountService bankAccountService;
    public List<BankAccountStatement> getUserAccountStatement(BankAccountStatementDto bankAccountStatementDto, String accountNumber) throws DataNotFoundException {
        BankAccount bankAccount = bankAccountService.getAccountByAccountNumber(accountNumber);
        List<TransactionType> transactionTypeList = transactionTypeRepository.findByBankAccountAndTransactionDateBetween(bankAccount,bankAccountStatementDto.getStartDate(),bankAccountStatementDto.getEndDate());
        List<BankAccountStatement> bankAccountStatementList = new ArrayList<>();
        for (TransactionType transactionType: transactionTypeList){
            BankAccountStatement bankAccountStatement = new BankAccountStatement();
            bankAccountStatement.setId(transactionType.getId());
            bankAccountStatement.setTransactionType(transactionType.getTransactionType());
            bankAccountStatement.setTransactionDate(transactionType.getTransactionDate().toString());
            bankAccountStatement.setDescription(transactionType.getDescription());
            bankAccountStatement.setDepositorOrWithDrawalName(transactionType.getDepositorOrWithDrawalName());
            bankAccountStatement.setCurrentBalance(transactionType.getCurrentBalance());
            bankAccountStatement.setAmount(transactionType.getAmount());
            bankAccountStatementList.add(bankAccountStatement);
        }
        return bankAccountStatementList;
    }
}

3. 修复Controller的请求方式问题

@GetMapping不建议搭配@RequestBody使用,改为@PostMapping更符合REST规范:

@RestController
public class TransactionController {
    @Autowired
    private TransactionTypeService transactionTypeService;
    @PostMapping("/account/statement/from/enteredDate")
    public ResponseEntity<List<BankAccountStatement>> getCustomerAccountStatement(@RequestBody BankAccountStatementDto bankAccountStatementDto,@RequestParam("accountNumber")String accountNumber) throws DataNotFoundException {
        return new ResponseEntity<>(transactionTypeService.getUserAccountStatement(bankAccountStatementDto,accountNumber),HttpStatus.OK);
    }
}

内容的提问来源于stack exchange,提问作者Ukeme Elijah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:40:42