Spring data jpa中Query和@Query分别返回map结果集

引用:html

http://blog.csdn.net/yingxiake/article/details/51016234java

http://blog.csdn.net/yingxiake/article/details/51016234spring

http://www.cnblogs.com/zj0208/p/6008627.htmlsql

 

Query的使用:数据库

在JPA 2.0 中咱们可使用entityManager.createNativeQuery()来执行原生的SQL语句。 但当咱们查询结果没有对应实体类时,query.getResultList()返回的是一个List<Object[]>。也就是说每行的数据被做为一个对象数组返回。
数组

常见的用法是这样的:session

复制代码
public void testNativeQuery(){ Query query = entityManager.createNativeQuery("select id, name, age from t_user"); List rows = query.getResultList(); for (Object row : rows) { Object[] cells = (Object[]) row; System.out.println("id = " + cells[0]); System.out.println("name = " + cells[1]); System.out.println("age = " + cells[2]); } } 
复制代码

这样用会使代码很是不容易让人理解, 究竟下标为0的元素究竟是什么, 不去数查询语句是不知道的,并且一旦查询语句被调整,Java代码也要一块儿调整。这时候咱们想若是返回的是Map的话,用起来会清晰的多。

惋惜的是JPA的API中并无提供这样的设置。其实不少JPA的底层实现都是支持返回Map对象的。例如:
EclipseLink的query.setHint(QueryHints.RESULT_TYPE, ResultType.Map); 
Hibernate的.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

因此,若是咱们想要返回Map而且肯定底层用的是某一种JPA的实现时咱们能够退而求其次, 牺牲跨实现的特性来知足咱们的需求:
post

 

复制代码
    public void testNativeQuery(){ Query query = entityManager.createNativeQuery("select id, name, age from t_user"); query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); List rows = query.getResultList(); for (Object obj : rows) { Map row = (Map) obj; System.out.println("id = " + row.get("ID")); System.out.println("name = " + row.get("NAME")); System.out.println("age = " + row.get("AGE")); } } 
或者
public List<Map> findMapBySql(String sqlStr) {
        Session session = getEntityManager().unwrap(Session.class);
        return session.createSQLQuery(sqlStr).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
    }
复制代码

 

这里须要注意的是, 用Map确定要比用Object数组来的效率低。因此你要看性能降低是否在可接受范围内。再就是在个人Hibernate 4.2.x的环境下,不管你原生SQL中写的是大写字母仍是小写字母,返回的字段名都是大写的。固然你能够经过自定义ResultTransformer的形式对字段名进行必定的处理, 甚至是返回本身须要的POJO。性能

 

还有一种更简单的办法:spa

 

Query query = em.createNativeQuery(sql,java.util.Map.class); 

 

这样就能够直接返回Map格式的结果集了。

 

@Query的使用

1. 一个使用@Query注解的简单例子

@Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2")
List<Book> findByPriceRange(long price1, long price2);

 

2.  Like表达式

@Query(value = "select name,author,price from Book b where b.name like %:name%")
List<Book> findByNameMatch(@Param("name") String name);

 

3. 使用Native SQL Query

所谓本地查询,就是使用原生的sql语句(根据数据库的不一样,在sql的语法或结构方面可能有所区别)进行查询数据库的操做。

@Query(value = "select * from book b where b.name=?1", nativeQuery = true) List<Book> findByName(String name);

 

4. 使用@Param注解注入参数

@Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price")
List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author, @Param("price") long price);

 

5. SPEL表达式(使用时请参考最后的补充说明)

   '#{#entityName}'值为'Book'对象对应的数据表名称(book)。

public interface BookQueryRepositoryExample extends Repository<Book, Long>{

       @Query(value = "select * from #{#entityName} b where b.name=?1", nativeQuery = true)
       List<Book> findByName(String name);

}

 

6. 一个较完整的例子

复制代码
public interface BookQueryRepositoryExample extends Repository<Book, Long> { @Query(value = "select * from Book b where b.name=?1", nativeQuery = true) List<Book> findByName(String name);// 此方法sql将会报错(java.lang.IllegalArgumentException),看出缘由了吗,若没看出来,请看下一个例子 @Query(value = "select name,author,price from Book b where b.price>?1 and b.price<?2") List<Book> findByPriceRange(long price1, long price2); @Query(value = "select name,author,price from Book b where b.name like %:name%") List<Book> findByNameMatch(@Param("name") String name); @Query(value = "select name,author,price from Book b where b.name = :name AND b.author=:author AND b.price=:price") List<Book> findByNamedParam(@Param("name") String name, @Param("author") String author, @Param("price") long price); }
复制代码

 

7.  解释例6中错误的缘由:

     由于指定了nativeQuery = true,即便用原生的sql语句查询。使用java对象'Book'做为表名来查天然是不对的。只需将Book替换为表名book。

@Query(value = "select * from book b where b.name=?1", nativeQuery = true) List<Book> findByName(String name);

 

8. 在这里咱们说下,spring data jpa的查询策略,spring data jpa能够利用建立方法进行查询,也能够利用@Query注释进行查询,那么若是在命名规范的方法上使用了@Query,那spring data jpa是执行咱们定义的语句进行查询,仍是按照规范的方法进行查询呢?看下查询策略

查询策略的配置能够在配置query-lookup-strategy,例如这样

<jpa:repositories base-package="com.liuxg.**.dao" repository-impl-postfix="Impl" query-lookup-strategy = "create-if-not-found" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" > </jpa:repositories>

它有三种值能够配置

  1. create-if-not-found(默认):若是经过 @Query指定查询语句,则执行该语句,若是没有,则看看有没有@NameQuery指定的查询语句,若是尚未,则经过解析方法名进行查询

  2. create:经过解析方法名字来建立查询。即便有 @Query,@NameQuery都会忽略

  3. use-declared-query:经过执行@Query定义的语句来执行查询,若是没有,则看看有没有经过执行@NameQuery来执行查询,尚未则抛出异常

@Query就先看到这里,下次再了解下怎么拓展spring data jpa 接口,例如我既想用sping data jpa的接口,但是我又想本身定义一些接口,咱们把他们合二为一呢??

 

补充说明(2017-01-12):

  有同窗提出来了,例子5中用'#{#entityName}'为啥取不到值啊?

  先来讲一说'#{#entityName}'究竟是个啥。从字面来看,'#{#entityName}'不就是实体类的名称么,对,他就是。

  实体类Book,使用@Entity注解后,spring会将实体类Book归入管理。默认'#{#entityName}'的值就是'Book'。

  可是若是使用了@Entity(name = "book")来注解实体类Book,此时'#{#entityName}'的值就变成了'book'。

  到此,事情就明了了,只须要在用@Entity来注解实体类时指定name为此实体类对应的表名。在原生sql语句中,就能够把'#{#entityName}'来做为数据表名使用。

相关文章
相关标签/搜索