使用ORM,EntityManager,@ Query的Spring Data Repository,处理自定义SQL查询的最优雅方式是什么?

时间:2016-01-25 06:52:55

标签: java spring hibernate jpa

我最近一直在学习Spring Boot框架,根据我的研究,我可以

  • 在maven依赖列表中包含Hibernate JPA实现,扩展CrudRepository并添加自定义方法

  • 使用Hibernate中的EntityManager执行自定义SQL查询

  • 使用注释@org.springframework.data.jpa.repository.Query

问题

  • 他们是否缓存我查询过的数据?

  • 他们有相同的表现吗?

  • 哪一个是最优雅的自定义SQL查询方式?如果没有,在使用Spring框架(不限于Repository模式)和Hibernate时,还有其他方法可以处理自定义SQL查询吗?

1。存储库方法

@Entity
@Table(name = Collection.TABLE_NAME)
public class Collection {
    public final static String TABLE_NAME = "collection";
    ...
}

public interface CollectionRepository extends CrudRepository<Collection, Integer> {
}

public class CollectionRepositoryImpl {
    @Autowired
    private CollectionRepository collectionRepository;

    public List<Collection> findCollectionsForSeason(int season, int count) {
        List<Collection> results = new ArrayList<>();

        for (Collection c : collectionRepository.findAll()) {
            if (c.getSeason() == season) {
                results.add(c);
            }
        }

        return results;
    }
}

2。 EntityManager方法

public class xxx {
    private EntityManager em;
    ...

    public List<Collection> findCollectionsForSeason(int season, int count) {
        String sqlString = String.format("SELECT * FROM `collection` WHERE `season`=%d LIMIT %d", season, count);
        return this.em.createNativeQuery(sqlString).getResultList();
    }
}

第3。 @Query方法

注意:下面的代码段错误,但我无法弄清楚如何正确执行此操作。因此,如果有人可以帮助我使用命名参数和限制子句(mysql)来实现本机查询,那就太好了。

public interface CollectionRepository extends CrudRepository<Collection, Integer> {
    @Query(value = "SELECT * FROM `collection` WHERE `season`=%d LIMIT %d", nativeQuery = true)
    List<Collection> findCollectionsForSeason(int season, int count) {
    }
}

谢谢!

3 个答案:

答案 0 :(得分:1)

  1. 您可以使用上述每种方法缓存数据。因为这是另一回事。您需要使用例如Ehcache或Redis,并为要缓存的方法提供<ProgressBar style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="10dp" android:layout_height="match_parent" android:layout_marginTop="@dimen/form_items_margin" android:layout_gravity="center" android:max="100" android:progress="90" android:progressDrawable="@drawable/progress_drawable_vertical" /> 注释。

  2. 非常相似,只要确保你不要搞砸了。我宁愿选择JPARepository和本地查询,但这是个人偏好的问题。您可以查看一些文章,例如:http://wiki.aiwsolutions.net/2014/03/18/spring-data-versus-traditional-jpa-implementation/

  3. 对于此:@Cacheable,您可以创建JPARepository方法而不是本机查询。这样的事情:

    @Query(value = "SELECT * FROM collection WHERE season=%d LIMIT %d", nativeQuery = true)

    在这里阅读更多内容: http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html

答案 1 :(得分:1)

所有这三种方法都使用底层的Hibernate实现来执行本机查询并获​​取结果(在第一个实现中,您将检索每个实体,因此性能会更差)。请记住,您可以将它们混合在一个存储库实现中,无需为一个存储库遵循相同的模式。

就个人而言,我倾向于使用你的第三种方法,在我看来这是最干净的方式,因为它让Spring处理查询而不需要你的代码处理实体管理器。

public interface CollectionRepository extends CrudRepository<Collection, Integer> {
    @Query(value = "SELECT * FROM collection WHERE season=:season LIMIT :count", nativeQuery = true)
    List<Collection> findCollectionsForSeason(@Param("season") int season, @Param("count") int count);
}

在实现本机查询时,请记住,如果要将它们转换为实体,则返回的列必须与映射的名称匹配。

每当您需要实现应在运行时处理的更复杂的查询时,请记住,您将能够提供扩展给定接口的自己的存储库实现。

答案 2 :(得分:1)

不要做任何这些事情。而不是扩展CrudRepository扩展PagingAndSortingRepository或(当您使用JPA时)JpaRepository。如何使用它以及如何限制结果在the reference guide中进行了解释。

public interface CollectionRepository extends PagingAndSortingRepository <Collection, Integer> {}

然后添加一个finder方法,该方法接受您的参数和Pageable参数。

List<Collection> findByReason(String reason, Pageable page);

现在,在您的服务中,您可以执行类似

的操作
return collectionRepository.findByReason(reason, new PageRequest(0, count));

如果您需要更灵活的查询,可以始终将分页方法与Specification结合使用。

public interface CollectionRepository 
    extends CrudRepository<Collection, Integer>,
            JpaSpecificationExecutor<Collection> {}

然后在你的服务中

return collectionRepository.findAll(new YourSpecification(), new PageRequest(0, count));

这允许非常灵活的查询生成(我们使用一般实现来提供大多数可搜索的数据表)。

基本上,它归结为使用框架(并理解它)而不是解决它。