我有一个Sping Boot 3.0应用程序,它从Spring Data repository获取一个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在从getReportData
方法返回Blob
后关闭了连接。当我尝试从Blob
获取字节时,这会导致以下错误:
SQLException:com.microsoft.sqlserver.jdbc.SQLServerException:连接已关闭。连接已关闭。
我可以通过使getValuations
成为transactional(即,将该方法注解为@Transactional
)来保持连接打开,但是由于锁定问题,数据库挂起。
我如何告诉Spring Data在没有transaction的情况下保持连接打开,以便我可以从Blob中检索字节?
- 注意:我不能使用byte[]作为
getReportData
的返回类型,因为数据将被截断到8000字节。 - 注意:我的过程
pValuation
是只读的。*
更新
我可以在不使用Spring Data JPA的情况下调用这个存储过程(并且没有transaction),如下所示:
@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在repository方法调用之后关闭连接,除非我有一个transaction(我不能使用它,因为DB SP挂起了B/c)。
1条答案
按热度按时间ecbunoof1#
如果不将
EntityManager
与createStoredProcedureQuery
一起使用,您可以看看SimpleJdbcCall
。API非常相似,您可以定义一次(作为bean或在构造函数中)并重用该定义。额外的好处是,提取结果的回调是在当前连接上操作的,因此它保持打开状态。Sping Boot 会自动配置一个
JdbcTemplate
,你可以重用它来创建一个SimpleJdbcCall
。沿着这些路线的东西应该会起作用。不确定代码是否完全正常,因为我是从我的头顶编码的。