我有一个Raspberry温度记录器使用Sqlite数据库,这是与我的嵌入式C++文明网络应用程序工作很好。
我想我会有一些乐趣,试图得到一些与Spring有关的东西。我可以让一些查询工作,但我几乎没有任何尝试与查询日期。
我使用org.xerial sqlit-JDBC3.36.0.3和com.enigmabridge Hibernate4-sqlite0.1.2来设置sqlite数据源。
在我的Pi上,返回数据并显示最后一天温度图的主要查询是:
SELECT timestamp, temp, id FROM temps WHERE timestamp > datetime('now', 'localtime', '-1 days');
但是这种类型的查询似乎不适用于JPA,因为查询的天数在单引号字符串文本中,因此任何参数都按原样传递。如果我直接指定查询中的天数,它将返回数据,但我希望将其作为param传递。
因此,我尝试在Spring中查询两次约会,如下所示:
LocalDate end = LocalDate.now();
LocalDate start = end.minusDays(2);
return temperatureRepository.findTemperaturesBetweenDates(start, end);
在存储库中使用此方法:
@Query("SELECT op FROM Temperature op WHERE timestamp between :startDate AND :endDate")
List<Temperature> findTemperaturesBetweenDates(@Param(value="startDate") LocalDate startDate, @Param(value="endDate") LocalDate endDate);
此查询不返回结果。同样,在没有参数的情况下,在查询中直接在单引号中指定日期是有效的,并返回数据。我也尝试过nativeQuery,但结果是一样的。
将Hibernate上的日志记录级别更改为跟踪,我可以看到正在使用的参数,它似乎正在将日期转换为划时代的时间。
/*从温度op中选择op,其中时间戳介于:startDate和:endDate */选择temperatur0_.timestamp作为timestam1__,temperatur0_.id作为id2__,temperatur0_.temp作为temp3__从temps temperatur0_选择时间戳在哪里?然后呢?Hibernate: /*从温度op中选择op,其中时间戳介于:startDate和:endDate */选择temperatur0_.timestamp作为timestam1__,temperatur0_.id作为id2__,temperatur0_.temp作为temp3__从temps temperatur0_选择时间戳在哪里?和? 2022-06-06 23:18:45.393调试9328 - nio-8080-exec-4 o.s.j.d.DriverManagerDataSource :创建到JDBC的新jdbc DriverManager连接:sqlite:src/main/resources/sqlTemplog.db 2022-06-06 23:18:45.394跟踪9328 -nio- nio-8080-exec-4 o.h.r.j.i.ResourceRegistryStandardImpl :注册语句/*从温度op中选择op,其中时间戳在:startDate和:endDate _/ SELECT temperatur0_.timestamp作为timestam1__,temperatur0_.id为id2__,temperatur0_.temp为temp3__,来自temps temperatur0_的时间戳在哪里?然后呢?parameters=null 2022-06-06 23:18:45.394跟踪9328 - nio-8080-exec-4 o.h.e.jdbc.internal.JdbcCoordinatorImpl :注册最后一次查询语句/从温度op中选择op,其中时间戳在:startDate和:endDate / select temperatur0_.timestamp作为timestam1__,temperatur0_.id作为id2__,temperatur0_.temp作为temp3__来自临时temp3__ temperatur0_,其中时间戳在哪里?和?_
2022-06-04 2022-06-06 23:18:45.394跟踪9328 - nio-8080-exec-4 o.h.type.descriptor.sql.BasicBinder :绑定参数1 as DATE - _parameters=null 2022-06-06 23:18:45.394跟踪9328 -- nio-8080-exec-4 o.h.type.descriptor.sql.BasicBinder :绑定参数2作为日期- 2022-06-06 2022-06-06 23:18:45.394痕量9328 -- nio-8080-exec-4 org.hibernate.loader.Loader_
o.h.r.j.i.ResourceRegistryStandardImpl :注册结果集org.sqlite.jdbc4.JDBC4ResultSet@23105e31 2022-06-06 23:18:45.394跟踪9328 -- nio-8080-exec-4 org.hibernate.loader.Loader :处理结果集2022-06 23:18:45.394org.hibernate.loader.Loader :完成处理结果集(0行) 2022-06-06 23:18:45.394跟踪9328 -nio-8080- org.hibernate.loader.Loader :水合总对象:0 2022-06-06 23:18:45.395跟踪9328 --nio-8080- o.h.r.j.i.ResourceRegistryStandardImpl :o.h.r.j.i.ResourceRegistryStandardImpl:从温度op释放语句[/从温度op中选择op,时间戳在:startDate和:endDate /选择temperatur0_.timestamp作为timestam1__,temperatur0_.id为id2__,temperatur0_.temp为temp3__,来自temps temperatur0_的时间戳在哪里?然后呢?
parameters=[ 1654297200000 , 1654470000000 __]] 2022-06-06 23:18:45.395跟踪9328 - nio-8080-exec-4 o.h.r.j.i.ResourceRegistryStandardImpl :关闭结果集org.sqlite.jdbc4.JDBC4ResultSet@23105e31 2022-06-06 23:18:45.395跟踪9328 -- nio-8080-exec-4 o.h.r.j.i.ResourceRegistryStandardImpl :关闭准备语句[/从温度op中选择op,时间戳为:startDate和:endDate */选择temperatur0_.timestamp作为timestam1__,temperatur0_.id为id2__,temperatur0_.temp为temp3__,来自temps temperatur0_的时间戳在哪里?然后呢?
parameters= 1654297200000 , 1654470000000 ]
我设法让它正常工作的唯一方法是在查询中使用unixepoch,并在Sqlite中转换参数:
@Query(value =("select timestamp, id, temp from temps where timestamp between DATETIME(ROUND(:startDate / 1000), 'unixepoch') AND DATETIME(ROUND(:endDate / 1000), 'unixepoch')"), nativeQuery = true)
List<Temperature> findTemperaturesTest(@Param(value="startDate") LocalDate startDate, @Param(value="endDate") LocalDate endDate);
有什么想法,如何使日期查询正确地使用Spring和Sqlite?谢谢
编辑:
好的,所以刚刚设法使-X days部分正常工作,但是我确实有其他的查询,它们将+/- days和date组合在一起,但是仍然无法正确地将日期传递给查询。
@Query("SELECT op FROM Temperature op WHERE id between 1 and 4 AND timestamp > datetime('now', 'localtime', '-' || :days || ' days')")
List<Temperature> findTemperaturesMinusDays(@Param(value="days") int days);
是的,所以这一切似乎都归结于Sqlite存储日期的方式。我的数据库将时间戳字段存储为字符串,如"2022-06-07 23:44:19",大多数数据库将日期存储为unix time。
没问题,我只是告诉它在查询数据库时将一个LocalDateTime转换成一个字符串。嗯,也许没那么容易。我尝试了“转换器”,“类型”,还有一些我忘记了的问题。这些都不管用。
我的第一次半成功尝试是将类中的数据类型更改为字符串,并在getter中进行转换。但这意味着@Query params也必须作为字符串传递。不是很好。
因此,我的解决方案是一个自定义存储库,它将一个LocalDateTime转换为一个字符串,并在查询中将这些参数设置为参数。
public class TemperatureRepositoryImpl implements TemperatureRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Temperature> findTemperaturesBetweenDates(LocalDateTime startDate, LocalDateTime endDate) {
Query query = entityManager.createNativeQuery("SELECT timestamp, temp, id FROM temps WHERE timestamp BETWEEN :startDate AND :endDate");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String startDateString = startDate.format(formatter);
String endDateString = endDate.format(formatter);
query.setParameter("startDate", startDateString);
query.setParameter("endDate", endDateString);
return query.getResultList();
}
编辑
差点就和那个扯上关系了。有两个问题--没有使用接口存储库,只有实现,日期不包括时间。最后,让它与TypedQuery一起工作:
public List<Temperature> findTemperaturesBetweenDates(LocalDateTime startDate, LocalDateTime endDate) {
TypedQuery<Temperature> query = entityManager.createQuery("SELECT op FROM Temperature op WHERE timestamp BETWEEN date(:startDate) AND date(:endDate)", Temperature.class);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String startDateString = startDate.format(formatter);
String endDateString = endDate.format(formatter);