如何让 Spring Data JPA 在没有事务的情况下保持连接打开?

问题描述 投票:0回答:1

我有一个 Spring Boot 3.0 应用程序,它从 Spring 数据存储库获取 Blob:

@Service
public class CarService {

    private final CarRepository carRepository;

    public Set<CarDto> getValuations(LocalDate date) {          
        Blob reportData = carRepository.getReportData("sedan,truck", date);
        try {
            byte[] b= reportData.getBytes(1, (int) reportData.length());
            log.debug("connection is closed by Spring Data JPA");
            //...
        } 

public interface CarRepository extends Repository<Car, Long> {
    
    @Procedure(value="pValuation", outputParameterName="reportData")
    Blob getReportData(String carTypes, LocalDate tradeDate);

不幸的是,Spring Data 在从

Blob
方法返回
getReportData
后关闭连接。当我尝试从
Blob
获取字节时,这会导致以下错误:

SQLException:com.microsoft.sqlserver.jdbc.SQLServerException:连接已关闭。连接已关闭。

我可以通过使

getValuations
事务化(即将方法注释为
@Transactional
)来保持连接打开,但随后数据库会因为锁定问题而挂起。

如何告诉 Spring Data 在没有事务的情况下保持连接打开,以便我可以从 Blob 检索字节?

注意:我不能使用 byte[] 作为

getReportData
的返回类型,因为数据将被截断为 8000 字节。

注意:我的程序

pValuation
是只读的。

更新

我可以在不使用 Spring Data JPA(并且没有事务)的情况下调用此存储过程,如下所示:

@Service
@RequiredArgsConstructor
@Slf4j
public class CarService {
  
    private final CarRepository carRepository;
    private final EntityManager em;

    public Set<CarDto> getValuations(LocalDate date) {
        
        StoredProcedureQuery q = em.createStoredProcedureQuery("pValuation");
        q.registerStoredProcedureParameter("carTypes", String.class, ParameterMode.IN);
        q.registerStoredProcedureParameter("tradeDate", LocalDate.class, ParameterMode.IN);
        q.registerStoredProcedureParameter("reportData", Blob.class, ParameterMode.OUT);
        q.setParameter("carTypes", "sedan,truck");
        q.setParameter("tradeDate", date);
        q.execute();
        
        Blob reportData = (Blob) q.getOutputParameterValue("reportData");
        
        log.debug("got Blob");
        try {
            byte[] b= reportData.getBytes(1, (int) reportData.length());
            log.debug("got bytes");
            return carRepository.getCarValuations(b);
        } 
        catch (SQLException convertBlobToBytesException) {
                log.error(convertBlobToBytesException.toString());
        }
    }

此代码之所以有效,是因为在读取字节时连接保持打开状态。据我所知,Spring Data 在存储库方法调用后关闭连接,除非我有事务(我不能使用事务,因为 DB SP 挂起)。

java spring hibernate spring-data-jpa spring-data
1个回答
0
投票

您可以查看

EntityManager
,而不是将 createStoredProcedureQuery
SimpleJdbcCall
一起使用。 API 非常相似,您可以定义一次(作为 bean 或在构造函数中)并重复使用该定义。额外的好处是提取结果的回调在当前连接上运行,因此它保持打开状态。

Spring Boot 自动配置一个

JdbcTemplate
,您可以重复使用它来创建
SimpleJdbcCall

SimpleJdbcCall sp = new SimpleJdbcCall(jdbcTemplate);
sp.declareParameters(new SqlParameter("carTypes", Types.VARCHAR),
new SqlParameter("tradeDate", Types.DATE), new SqlOutParameter("reportData", Types.BLOB, new RowMapper())

© www.soinside.com 2019 - 2024. All rights reserved.