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>
它有三种值可以配置
create-if-not-found(默认):如果通过 @Query指定查询语句,则执行该语句,如果没有,则看看有没有@NameQuery指定的查询语句,如果还没有,则通过解析方法名进行查询
create:通过解析方法名字来创建查询。即使有 @Query,@NameQuery都会忽略
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}'来作为数据表名使用。
Spring data jpa中Query和@Query分别返回map结果集的更多相关文章
- 在Spring Data JPA 中使用Update Query更新实体类
对于 Spring Data JPA 使用的时间不长,只有两年时间.但是踩过坑的却不少. 使用下列代码 @Modifying @Query("update User u set u.firs ...
- 【hql】spring data jpa中 @Query使用hql查询 问题
spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...
- Spring data JPA中使用Specifications动态构建查询
有时我们在查询某个实体的时候,给定的条件是不固定的,这是我们就需要动态 构建相应的查询语句,在JPA2.0中我们可以通过Criteria接口查询,JPA criteria查询.相比JPQL,其优势是类 ...
- Spring Data JPA中的动态查询 时间日期
功能:Spring Data JPA中的动态查询 实现日期查询 页面对应的dto类private String modifiedDate; //实体类 @LastModifiedDate protec ...
- 如何在Spring Data JPA中引入Querydsl
一.环境说明 基础框架采用Spring Boot.Spring Data JPA.Hibernate.在动态查询中,有一种方式是采用Querydsl的方式. 二.具体配置 1.在pom.xml中,引入 ...
- Spring Data JPA中CrudRepository与JpaRepository的不同
使用Spring Data JPA CrudRepository 和JpaRepository 的好处: 继承这些接口,可以使Spring找到自定义的数据库操作接口,并生成代理类,后续可以注入到Spr ...
- Spring Data JPA 中常用注解
一.java对象与数据库字段转化 1.@Entity:标识实体类是JPA实体,告诉JPA在程序运行时生成实体类对应表 2.@Table:设置实体类在数据库所对应的表名 3.@Id:标识类里所在变量为主 ...
- spring data JPA 中的多属性排序
在此介绍我所用的一种方式: 第一步,引包 import org.springframework.data.domain.Sort;import org.springframework.data.dom ...
- 【spring data jpa】spring data jpa 中的update 更新字段,如果原字段值为null不处理,不为null则在原来的值上加一段字符串
示例代码: /** * 如果barCode字段值为null则不处理 * 如果barCode字段值不为null则在原本值的前面拼接 del: * @param dealer * @return */ @ ...
随机推荐
- qt之旅-1纯手写Qt界面
通过手写qt代码来认识qt程序的构成,以及特性.设计一个查找对话框.以下是设计过程 1 新建一个empty qt project 2 配置pro文件 HEADERS += \ Find.h QT += ...
- QT学习笔记(一)——ui的认识
////////////2015/08/06/////////////////// ///////////by xbw////////////////////////// //////////环境 Q ...
- 关于wireshark
1 对https进行抓包,或者说抓包经过了ssl加密的包 只要有rsa private key就可以了. https://wiki.wireshark.org/SSL 2 对浏览器访问的https的网 ...
- 动态追踪技术 Dynamic Tracing
https://openresty.org/posts/dynamic-tracing/ 工欲性能调优,必先利其器(2)- 火焰图| PingCAP https://pingcap.com/blog- ...
- JDBC连接数据库核心代码
1.Oracle数据库 Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url ...
- Linux文件锁【转】
本文转载自:http://blog.csdn.net/dragon_li_chen/article/details/17147911 一.文件锁的分类: 翻阅参考资料,你会发现文件锁可以进行很多的分类 ...
- 什么叫强类型的DATASET ?对DATASET的操作处理?强类型DataSet的使用简明教程
强类型DataSet,是指需要预先定义对应表的各个字段的属性和取值方式的数据集.对于所有这些属性都需要从DataSet, DataTable, DataRow继承,生成相应的用户自定义类.强类型的一个 ...
- android编程取消标题栏方法(appcompat_v7、Theme.NoTitleBar)
方式一:编码方式 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstance ...
- 牛客练习赛13D:幸运数字Ⅳ(康托展开) F:关键字排序
链接:https://www.nowcoder.com/acm/contest/70/D 题目: 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7. 比如说,47.744.4都是幸运数字而5.1 ...
- package-lock.json到底是干嘛的?(转载)
package-lock.json到底是干嘛的? https://mp.weixin.qq.com/s/NaVVljKrQAFmHMdbkaYmPg## nvm-windows https://git ...