zoukankan      html  css  js  c++  java
  • Spring data jpa中Query和@Query分别返回map结果集

    引用:

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

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

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

    Query的使用:

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

    常见的用法是这样的:

    复制代码
    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的实现时我们可以退而求其次, 牺牲跨实现的特性来满足我们的需求:

    复制代码
        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。

    还有一种更简单的办法:

    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}'来作为数据表名使用。

  • 相关阅读:
    ExtJS小技巧
    Oracle 表的行数、表占用空间大小,列的非空行数、列占用空间大小 查询
    NPM 私服
    IDEA 不编译java以外的文件
    SQL 引号中的问号在PrepareStatement 中不被看作是占位符
    Chrome 浏览器自动填表呈现淡黄色解决
    批量删除Maven 仓库未下载成功.lastupdate 的文件
    Oracle 11g 监听很慢,由于监听日志文件太大引起的问题(Windows 下)
    Hibernate 自动更新表出错 建表或添加列,提示标识符无效
    Hibernate 自动更新表出错 More than one table found in namespace
  • 原文地址:https://www.cnblogs.com/wucongyun/p/6730582.html
Copyright © 2011-2022 走看看