本文介绍了如何使用Spring Data JPA保留JSR-310类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Spring Data JPA 1.8与Java 8 Date / Time API JSR-310一起使用。



一切似乎都有效,直到我尝试全部两个LocalDateTimes之间的车辆。
返回的实体数量似乎与它应该的数量只有松散的相关性。



实体



  @Repository 
public interface VehicleRepository扩展JpaRepository< Vehicle,Long> {

列表< Vehicle> findByDateTimeBetween(LocalDateTime begin,LocalDateTime end);

}



存储库



  @Entity 
@Table(name =VEHICLE)
public class Vehicle implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name =IDX,nullable = false,unique = true)
@GeneratedValue(strategy = GenerationType.AUTO)
private long vehicleId;

@Column(name =DATE_TIME,nullable = false)
private LocalDateTime dateTime = LocalDateTime.now();

// Getters and Setters

}



相关依赖



 < dependency> 
< groupId> org.springframework.data< / groupId>
< artifactId> spring-data-jpa< / artifactId>
< version> 1.8.0.RELEASE< / version>
< / dependency>
< dependency>
< groupId> org.springframework< / groupId>
< artifactId> spring-aspects< / artifactId>
< version> 4.0.9.RELEASE< / version>
< / dependency>
< dependency>
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-core< / artifactId>
< version> 4.3.8.Final< / version>
< / dependency>
< dependency>
< groupId> org.hibernate< / groupId>
< artifactId> hibernate-entitymanager< / artifactId>
< version> 4.3.8.Final< / version>
< / dependency>
< dependency>
< groupId> com.h2database< / groupId>
< artifactId> h2< / artifactId>
< version> 1.4.186< / version>
< / dependency>
< dependency>
< groupId> com.zaxxer< / groupId>
< artifactId> HikariCP< / artifactId>
< version> 2.3.5< / version>
< / dependency>



测试失败示例



  @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({classpath *:applicationContextTesting.xml})
@Transactional
public class VehicleRepositoryTest {

@Autowired
private VehicleRepository vehicleRepository;

@Test
public void testVehicleBetween(){
//给定
Vehicle vehicleMarch1Twelve = new Vehicle();
Vehicle vehicleMarch1Eighteen = new Vehicle();
Vehicle vehicleMarch2Five = new Vehicle();
Vehicle vehicleMarch2Six = new Vehicle();
LocalDateTime march1Twelve = LocalDateTime.of(2015,Month.MARCH,1,12,0);
LocalDateTime march1Eighteen = LocalDateTime.of(2015,Month.MARCH,1,18,0);
LocalDateTime march2Five = LocalDateTime.of(2015,Month.MARCH,2,5,0);
LocalDateTime march2Six = LocalDateTime.of(2015,Month.MARCH,2,6,0);
vehicleMarch1Twelve.setDateTime(march1Twelve);
vehicleMarch1Eighteen.setDateTime(march1Eighteen);
vehicleMarch2Five.setDateTime(march2Five);
vehicleMarch2Six.setDateTime(march2Six);

vehicleRepository.save(vehicleMarch1Twelve);
vehicleRepository.save(vehicleMarch1Eighteen);
vehicleRepository.save(vehicleMarch2Five);
vehicleRepository.save(vehicleMarch2Six);
vehicleRepository.flush();

//当
List< Vehicle> allVehicles = vehicleRepository.findByDateTimeBetween(
march1Twelve,
march2Six);
列表< Vehicle> allVehicles2 = vehicleRepository.findByDateTimeBetween(
march1Twelve.minusMinutes(2),
march2Six.plusMinutes(2));
列表< Vehicle> threeVehicles = vehicleRepository.findByDateTimeBetween(
march1Twelve.plusMinutes(2),
march2Six);
列表< Vehicle> twoVehicles = vehicleRepository.findByDateTimeBetween(
march1Twelve.plusMinutes(2),
march2Six.minusMinutes(2));
列表< Vehicle> oneVehicles = vehicleRepository.findByDateTimeBetween(
march1Twelve.plusMinutes(2),
march2Six.minusHours(3));

//然后
Assert.assertTrue(size was+ allVehicles.size(),allVehicles.size()== 4);
Assert.assertTrue(size was+ allVehicles2.size(),allVehicles2.size()== 4);
Assert.assertTrue(size was+ threeVehicles.size(),threeVehicles.size()== 3);
Assert.assertTrue(size was+ twoVehicles.size(),twoVehicles.size()== 2);
Assert.assertTrue(size was+ oneVehicles.size(),oneVehicles.size()== 1);
Assert.assertTrue(oneVehicles.get(0).getDateTime()。equals(march1Eighteen));
}

}

第一个List包含2个元素(应该是4)。所有其他列表包含 0 元素!
鉴于第二个请求的时间跨度比第一个要大。



有人可以告诉我我做错了吗?






编辑



谢谢快速回答。
我能够通过将org.springframework.data.jpa.convert.threeten添加到packagesToScan属性来解决此问题。现在它似乎正常工作。



这里的参考是我工作的数据库相关(测试)配置。

 < bean id =hikariConfigclass =com.zaxxer.hikari.HikariConfig> 
< property name =driverClassNamevalue =org.h2.Driver/>
< property name =jdbcUrlvalue =jdbc:h2:mem:testing/>
< property name =usernamevalue =interface/>
< property name =passwordvalue =/>
< property name =connectionTestQueryvalue =SELECT 1/>
< / bean>

< bean id =dataSourceclass =com.zaxxer.hikari.HikariDataSource>
< constructor-arg index =0ref =hikariConfig/>
< / bean>

< bean id =transactionManagerclass =org.springframework.orm.jpa.JpaTransactionManager>
< property name =entityManagerFactoryref =entityManagerFactory/>
< / bean>

< tx:annotation-driven />

< bean id =hibernateJpaVendorAdapterclass =org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter/>

< bean id =entityManagerFactoryclass =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
< property name =dataSourceref =dataSource/>
< property name =jpaVendorAdapterref =hibernateJpaVendorAdapter/>
< property name =packagesToScanvalue =com.company.project.domain,org.springframework.data.jpa.convert.threeten/>
< property name =jpaProperties>
< props>
< prop key =hibernate.dialect> org.hibernate.dialect.H2Dialect< / prop>
< prop key =hibernate.hbm2ddl.auto> update< / prop>
< / props>
< / property>
< / bean>

< jpa:repositories base-package =com.company.project.daotransaction-manager-ref =transactionManager
entity-manager-factory-ref =entityManagerFactory />


解决方案

更新:如果您需要,以下答案有效继续使用Hibernate版本< 5.0。 Hibernate 5.0支持开箱即用的持久化JSR-310日期/时间类型。即如果您使用的是Hibernate 5.0或更高版本,那么即可。其他人,请继续阅读。



这一点的根本原因在于,没有一个广泛使用的JPA提供商实际上支持开箱即用的JSR-310类型。但是,从Spring Data JPA 1.8.0开始,我们发布了JPA 2.0转换器,它将非时区划分的JSR-310类型转换为遗留的 Date ,以便它们可以保留为了实现这个目的,只需注册 org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters 作为您的提供商的托管JPA类之一。有几种方法可以做到这一点:在非常标准的JPA设置中,您可以在 persistence.xml 中列出它。在基于 LocalContainerEntityManagerFactoryBean 的设置中,您只需将该类的包添加到 packagesToScan 属性即可。如果你正在使用Spring Boot将类添加到 @EntityScan 注释就可以了。



后者是更详细地描述了,涵盖Spring数据发布列车名为Fowler的新功能


I am trying to use Spring Data JPA 1.8 with the Java 8 Date/Time API JSR-310.

Everything seems to work, until I try to get all Vehicles between two LocalDateTimes.The number of Entities returned seems to only have a loose correlation with the number it should.

Entity

@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, Long> {

    List<Vehicle> findByDateTimeBetween(LocalDateTime begin, LocalDateTime end);

}

Repository

@Entity
@Table(name = "VEHICLE")
public class Vehicle implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id
  @Column(name = "IDX", nullable = false, unique = true)
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long vehicleId;

  @Column(name = "DATE_TIME", nullable = false)
  private LocalDateTime dateTime = LocalDateTime.now();

  // Getters and Setters

}

Relevant Dependencies

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.8.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.0.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.8.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.8.Final</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.186</version>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.3.5</version>
    </dependency>

Failing Test Example

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:applicationContextTesting.xml"})
@Transactional
public class VehicleRepositoryTest {

    @Autowired
    private VehicleRepository vehicleRepository;

    @Test
    public void testVehicleBetween() {
        // Given
        Vehicle vehicleMarch1Twelve = new Vehicle();
        Vehicle vehicleMarch1Eighteen = new Vehicle();
        Vehicle vehicleMarch2Five = new Vehicle();
        Vehicle vehicleMarch2Six = new Vehicle();
        LocalDateTime march1Twelve = LocalDateTime.of(2015, Month.MARCH, 1, 12, 0);
        LocalDateTime march1Eighteen = LocalDateTime.of(2015, Month.MARCH, 1, 18, 0);
        LocalDateTime march2Five = LocalDateTime.of(2015, Month.MARCH, 2, 5, 0);
        LocalDateTime march2Six = LocalDateTime.of(2015, Month.MARCH, 2, 6, 0);
        vehicleMarch1Twelve.setDateTime(march1Twelve);
        vehicleMarch1Eighteen.setDateTime(march1Eighteen);
        vehicleMarch2Five.setDateTime(march2Five);
        vehicleMarch2Six.setDateTime(march2Six);

        vehicleRepository.save(vehicleMarch1Twelve);
        vehicleRepository.save(vehicleMarch1Eighteen);
        vehicleRepository.save(vehicleMarch2Five);
        vehicleRepository.save(vehicleMarch2Six);
        vehicleRepository.flush();

        // when
        List<Vehicle> allVehicles = vehicleRepository.findByDateTimeBetween(
            march1Twelve,
            march2Six);
        List<Vehicle> allVehicles2 = vehicleRepository.findByDateTimeBetween(
            march1Twelve.minusMinutes(2),
            march2Six.plusMinutes(2));
        List<Vehicle> threeVehicles = vehicleRepository.findByDateTimeBetween(
            march1Twelve.plusMinutes(2),
            march2Six);
        List<Vehicle> twoVehicles = vehicleRepository.findByDateTimeBetween(
            march1Twelve.plusMinutes(2),
            march2Six.minusMinutes(2));
        List<Vehicle> oneVehicles = vehicleRepository.findByDateTimeBetween(
            march1Twelve.plusMinutes(2),
            march2Six.minusHours(3));

        // then
        Assert.assertTrue("size was " + allVehicles.size(), allVehicles.size() == 4);
        Assert.assertTrue("size was " + allVehicles2.size(), allVehicles2.size() == 4);
        Assert.assertTrue("size was " + threeVehicles.size(), threeVehicles.size() == 3);
        Assert.assertTrue("size was " + twoVehicles.size(), twoVehicles.size() == 2);
        Assert.assertTrue("size was " + oneVehicles.size(), oneVehicles.size() == 1);
        Assert.assertTrue(oneVehicles.get(0).getDateTime().equals(march1Eighteen));
    }

}

The first List contains 2 elements (should be 4). All other List contain 0 elements!Given the second request is for a greater timespan than the first.

Can someone tell me what I am doing wrong?


Edit

Thank you @Oliver Gierke for the quick answer.I was able to fix the issue by adding "org.springframework.data.jpa.convert.threeten" to the packagesToScan property. Now it seems to work properly.

As reference here is my working Database related (testing) configuration.

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="jdbcUrl" value="jdbc:h2:mem:testing"/>
    <property name="username" value="interface"/>
    <property name="password" value=""/>
    <property name="connectionTestQuery" value="SELECT 1" />
</bean>

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <constructor-arg index="0" ref="hikariConfig"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven/>

<bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
    <property name="packagesToScan" value="com.company.project.domain,org.springframework.data.jpa.convert.threeten"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
        </props>
    </property>
</bean>

<jpa:repositories base-package="com.company.project.dao" transaction-manager-ref="transactionManager"
                  entity-manager-factory-ref="entityManagerFactory"/>
解决方案

UPDATE: The answer below is valid if you need to stay on a Hibernate version < 5.0. Hibernate 5.0 supports persisting JSR-310 date/time types out of the box. I.e. if you are on Hibernate 5.0 or newer, Adam's answer is the way to go. Everyone else, read on.

The root cause for this at none of the widely used JPA providers actually support JSR-310 types out of the box yet. However, as of Spring Data JPA 1.8.0 we ship JPA 2.0 converters that will translate non-time-zoned JSR-310 types into a legacy Date so that they can be persisted as is.

To get this working, simply register org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters as one of the managed JPA classes with your provider. There's a couple of way to do that: in a very standard JPA setup you list it in your persistence.xml. In a LocalContainerEntityManagerFactoryBean based setup you can just add the package of the class to the packagesToScan property. If you're using Spring Boot adding the class to the @EntityScan annotation does the trick.

The latter is described in a bit more detail in the blog post covering the new features the Spring Data release train named Fowler ships

这篇关于如何使用Spring Data JPA保留JSR-310类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 19:01