Spring JPA 使用@Query return 两个 DB2 TIMESTAMP 值之间的数据
Spring JPA Using @Query to return data between two DB2 TIMESTAMP values
我正在写一个 Springboot JPA REST API,它与 DB2 数据库对话,应该查询一个包含 TIMESTAMP
字段的 table。
使用 SQL,过滤两个 TIMESTAMP 之间的行的 DB2 查询如下所示,它将 return 来自我的测试数据的 1 条记录:
SELECT * FROM CARS WHERE SOLD_DATE BETWEEN '2020-01-01' AND '2022-01-01'
因为我使用的是 Spring Data JPA,所以我定义了 CarEntity
,它有一个 java.sql.Timestamp
字段
@Entity
public class CarEntity {
....
Timestamp soldDate;
...
//getters and setters
}
我正在尝试检索上述 SQL 查询中的数据。
为此,我在 Postman 中将开始和结束数据作为 Long
值传递,通过 URL 表示开始和结束日期,例如
http://localhost:8080/cars/sold/1420070400/1640995200
此端点命中我的控制器方法,该方法将 Long
转换为 java.sql.Date
并将其传递给存储库,在存储库中,我使用如下所示的 @Query
注释:
@Repository
public interface CarRepository extends JpaRepository<CarEntity, Timestamp>{
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between :startDate and :endDate")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
}
然而,这不起作用,它 return 没有数据,虽然我知道它应该 return 我 1 条记录。
但是如果我像下面这样硬编码开始和结束日期,我会得到 1 条记录:
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between '2020-01-01' and '2022-01-01'")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
当然,问题在于我硬编码了 startDate 和 endDate,而不是使用传递给 getCarsSoldBetween()
方法的那些。
UPDATE-1
感谢@HYUNJUN,我添加了一些更改:
- 我像以前一样在我的实体中使用
java.sql.Timestamp
但我的
控制器、服务和存储库使用 java.util.Date
而不是
java.sql.Date
我最初使用的。
- 在我的 application.properties 下面添加,以便能够查看在 SQL 中传递了哪些参数(请注意,这会显着降低速度,因此仅用于调试目的):
logging.level.org.hibernate.sql=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
现在,当我转到 DB2 Bench 并发出以下查询时,我将返回正确的 2 行:
SELECT * FROM MYSCHEMA.CARS WHERE SOLD_TIMESTAMP BETWEEN '2021-10-04 15:00:00' AND '2021-10-20 00:00:00';
// RETURNS 2 ROWS
但是,我的存储库查询如下所示:
@Repository
public interface CarRepository extends JpaRepository<CarEntity, Timestamp>{
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between :startDate and :endDate")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
}
, return 没什么,我希望 return 2 行,因为开始日期和结束日期与日志输出相同:
type.descriptor.sql.BasicBinder binding parameter [1] as [TIMESTAMP] - [Mon Oct 04 15:00:00 PDT 2021]
type.descriptor.sql.BasicBinder binding parameter [2] as [TIMESTAMP] - [Wed Oct 20 00:00:00 PDT 2021]
因此,我将通过相同的日期范围并期望得到相同的结果,但这并没有发生
我写的代码和你上面的代码几乎一样。但是我没有遇到你提到的问题。我在下面上传我的代码。你为什么不比较我的代码和你的代码?
package com.springboot.springbootinternals.db2;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class Db2Controller {
private final CarRepository carRepository;
@GetMapping("db2/{start-date}/{end-date}")
public String db2(
@PathVariable("start-date") Long startDate,
@PathVariable("end-date") Long endDate
) {
carRepository.save(Car.builder().date(new Timestamp(1420070401L * 1000)).build());
Date start = new Date(TimeUnit.SECONDS.toMillis(startDate));
Date end = new Date(TimeUnit.SECONDS.toMillis(endDate));
List<Car> cars = carRepository.findAll(start, end);
System.out.println(">>> " + cars);
return "success";
}
}
@Entity
@Builder
@NoArgsConstructor
@ToString
@AllArgsConstructor
class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Timestamp date;
}
@Repository
interface CarRepository extends JpaRepository<Car, Long> {
@Query("select c from Car c where c.date between :startDate and :endDate")
List<Car> findAll(Date startDate, Date endDate);
}
此外,将此选项放入 applicaion.yml 以检查是否将正确的值传递给 SQL。
logging:
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql:
BasicBinder: TRACE # show_parameter_value
像这样。
您可以使用以下代码检索所需的结果
@Repository
public interface CarEntityRepository extends JpaRepository<CarEntity,Long> {
@Query("SELECT c FROM CarEntity c WHERE c.carModel like %:model% and c.soldDate > :start and c.soldDate < :end ")
List<CarEntity> getCarsSoldBetween(@Param("model") String model, @Param("start") Date start, @Param("end") Date end);
}
我最终使用 java.sql.Timestamp
将它与我的 CarEntity 一起使用,如最初发布的那样,但这不会正确过滤数据,我会不断从我的控制器获取不同的记录与来自 SQL [=30 的记录=].
我发现像我在上面使用 java.sql.Date
或 java.sql.Timestamp
和 java.util.Date
那样混合日期类型很可能是造成这种情况的原因,我怀疑日期转换已关闭导致我的控制器 return 我的数据错误。
然后我读了这篇文章 https://thorben-janssen.com/hibernate-jpa-date-and-time/ 并意识到即使我的 DB2 table 使用 TIMESTAMP,我也可以使用 java.sql.Date
。
因此,我修改了我的控制器、服务、存储库和实体以使用 java.util.Date
而不是使用 java.sql.Date
或 java.sql.Timestamp
。
这解决了我的问题。
我正在写一个 Springboot JPA REST API,它与 DB2 数据库对话,应该查询一个包含 TIMESTAMP
字段的 table。
使用 SQL,过滤两个 TIMESTAMP 之间的行的 DB2 查询如下所示,它将 return 来自我的测试数据的 1 条记录:
SELECT * FROM CARS WHERE SOLD_DATE BETWEEN '2020-01-01' AND '2022-01-01'
因为我使用的是 Spring Data JPA,所以我定义了 CarEntity
,它有一个 java.sql.Timestamp
字段
@Entity
public class CarEntity {
....
Timestamp soldDate;
...
//getters and setters
}
我正在尝试检索上述 SQL 查询中的数据。
为此,我在 Postman 中将开始和结束数据作为 Long
值传递,通过 URL 表示开始和结束日期,例如
http://localhost:8080/cars/sold/1420070400/1640995200
此端点命中我的控制器方法,该方法将 Long
转换为 java.sql.Date
并将其传递给存储库,在存储库中,我使用如下所示的 @Query
注释:
@Repository
public interface CarRepository extends JpaRepository<CarEntity, Timestamp>{
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between :startDate and :endDate")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
}
然而,这不起作用,它 return 没有数据,虽然我知道它应该 return 我 1 条记录。
但是如果我像下面这样硬编码开始和结束日期,我会得到 1 条记录:
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between '2020-01-01' and '2022-01-01'")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
当然,问题在于我硬编码了 startDate 和 endDate,而不是使用传递给 getCarsSoldBetween()
方法的那些。
UPDATE-1
感谢@HYUNJUN,我添加了一些更改:
- 我像以前一样在我的实体中使用
java.sql.Timestamp
但我的 控制器、服务和存储库使用java.util.Date
而不是java.sql.Date
我最初使用的。 - 在我的 application.properties 下面添加,以便能够查看在 SQL 中传递了哪些参数(请注意,这会显着降低速度,因此仅用于调试目的):
logging.level.org.hibernate.sql=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
现在,当我转到 DB2 Bench 并发出以下查询时,我将返回正确的 2 行:
SELECT * FROM MYSCHEMA.CARS WHERE SOLD_TIMESTAMP BETWEEN '2021-10-04 15:00:00' AND '2021-10-20 00:00:00';
// RETURNS 2 ROWS
但是,我的存储库查询如下所示:
@Repository
public interface CarRepository extends JpaRepository<CarEntity, Timestamp>{
@Query("select c from CarEntity c where c.carModel = 'Toyota' and c.soldDate between :startDate and :endDate")
List<CarEntity> getCarsSoldBetween(Date startDate, Date endDate);
}
, return 没什么,我希望 return 2 行,因为开始日期和结束日期与日志输出相同:
type.descriptor.sql.BasicBinder binding parameter [1] as [TIMESTAMP] - [Mon Oct 04 15:00:00 PDT 2021]
type.descriptor.sql.BasicBinder binding parameter [2] as [TIMESTAMP] - [Wed Oct 20 00:00:00 PDT 2021]
因此,我将通过相同的日期范围并期望得到相同的结果,但这并没有发生
我写的代码和你上面的代码几乎一样。但是我没有遇到你提到的问题。我在下面上传我的代码。你为什么不比较我的代码和你的代码?
package com.springboot.springbootinternals.db2;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class Db2Controller {
private final CarRepository carRepository;
@GetMapping("db2/{start-date}/{end-date}")
public String db2(
@PathVariable("start-date") Long startDate,
@PathVariable("end-date") Long endDate
) {
carRepository.save(Car.builder().date(new Timestamp(1420070401L * 1000)).build());
Date start = new Date(TimeUnit.SECONDS.toMillis(startDate));
Date end = new Date(TimeUnit.SECONDS.toMillis(endDate));
List<Car> cars = carRepository.findAll(start, end);
System.out.println(">>> " + cars);
return "success";
}
}
@Entity
@Builder
@NoArgsConstructor
@ToString
@AllArgsConstructor
class Car {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Timestamp date;
}
@Repository
interface CarRepository extends JpaRepository<Car, Long> {
@Query("select c from Car c where c.date between :startDate and :endDate")
List<Car> findAll(Date startDate, Date endDate);
}
此外,将此选项放入 applicaion.yml 以检查是否将正确的值传递给 SQL。
logging:
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql:
BasicBinder: TRACE # show_parameter_value
像这样。
您可以使用以下代码检索所需的结果
@Repository
public interface CarEntityRepository extends JpaRepository<CarEntity,Long> {
@Query("SELECT c FROM CarEntity c WHERE c.carModel like %:model% and c.soldDate > :start and c.soldDate < :end ")
List<CarEntity> getCarsSoldBetween(@Param("model") String model, @Param("start") Date start, @Param("end") Date end);
}
我最终使用 java.sql.Timestamp
将它与我的 CarEntity 一起使用,如最初发布的那样,但这不会正确过滤数据,我会不断从我的控制器获取不同的记录与来自 SQL [=30 的记录=].
我发现像我在上面使用 java.sql.Date
或 java.sql.Timestamp
和 java.util.Date
那样混合日期类型很可能是造成这种情况的原因,我怀疑日期转换已关闭导致我的控制器 return 我的数据错误。
然后我读了这篇文章 https://thorben-janssen.com/hibernate-jpa-date-and-time/ 并意识到即使我的 DB2 table 使用 TIMESTAMP,我也可以使用 java.sql.Date
。
因此,我修改了我的控制器、服务、存储库和实体以使用 java.util.Date
而不是使用 java.sql.Date
或 java.sql.Timestamp
。
这解决了我的问题。