Hibernate:命名SQL查询

命名SQL查询顾名思义就是将SQL语句从程序中抽出来,放在注解中管理,然后给每个SQL查询起一个名称,在程序中仅需要调用此名称即可,从而可以更好的提高程序的解耦。

hibernate允许使用@NamedNativeQuery注解来定义命名的原生SQL查询,如果有多个命名查询,则使用@NamedNativeQueries注解来管理。


下面@NamedNativeQuery注解支持的属性:

name:指定命名SQL查询的名称 必须具备属性

query 指定命名SQL查询的查询语句 必须具备属性

resultClass 在简单查询中将查询结果映射成指定实体类的实例,类似于addEntity()作用。 非必须具备属性

resultSetMapping 该属性指定一个SQL结果映射的名称(该结果映射需要使用@SqlResultSetMapping定义),

            用于使用该结果映射来转换查询结果集。

简单查询时我们使用resultClass将查询结果转化为相应实体就可以了,但是如果是查询数据列较多,而且程序希望同时进行标量查询、实体查询,那就必须借助于resultSetMapping。

如果需要使用@NamedNativeQuery注解指定resultSetMapping属性(也就是需要复杂查询时)则还需要使用@SqlResultSetMapping定义SQL结果映射,@SqlResultSetMapping的作用就是将查询到的结果集转换为标量查询或者实体查询,类似于SQLQuery对象的addScalar()或者addEntity()方法的功能。

可能对于resultSetMapping和@SqlResultSetMapping两者容易混淆,搞不清楚到底是干什么的,通俗点讲就是 @SqlResultSetMapping是制定结果映射规则的,结果集是转化为标量查询还是实体查询我制定。 resultSetMapping是通过上面制定的映射名称引用这个结果映射的。


下面是@SqlResultSetMapping支持的属性

name 指定SQL结果映射的名称(上面说的,咱们通过resultSetMapping引用)必需属性

columns 该属性的值为@ColumnResult注解数组,每个@ColumnResult注解定义一个标量查询

entities 该属性的值为@EntityResult注解数组,每个@EntityResult注解定义一个实体查询

class 该属性的值为@ConstructorResult注解数组,每个@ConstructorResult负责将指定的多列转化为普通类对应的     属性

上面的@ColumnResult注解作用类似于SQLQuery对象的addScalar()作用,将结果集转换为标量查询

同样@EntityResult注解作用类似于SQLQuery对象的addEntity()作用,将结果集转换为标量查询

下面是实例:

一:先是通过resultClass就可以完成结果转换的简单查询


  1. // 定义一个命名SQL查询,其名称为simpleQuery  
  2. @NamedNativeQuery(name="simpleQuery"  
  3.     // 指定命名SQL查询对应的SQL语句  
  4.     , query="select s.*  from student_inf s"  
  5.     // 指定将查询结果转换为Student实体  
  6.     , resultClass=Student.class)  
  7. @Entity  
  8. @Table(name="student_inf")  
  9. public class Student  
  10. {  
  11.     // 代表学生学号的成员变量,将作为标识属性  
  12.     @Id @Column(name="student_id")  
  13.     private Integer studentNumber;  
  14.     // 代表学生姓名的成员变量  
  15.     private String name;  
  16.     // 该学生的所有选课记录对应的关联实体  
  17.     @OneToMany(targetEntity=Enrolment.class  
  18.         , mappedBy="student" , cascade=CascadeType.REMOVE)  
  19.     private Set<Enrolment> enrolments  
  20.         = new HashSet<>();  
  21.   
  22.     // 无参数的构造器  
  23.     public Student()  
  24.     {  
  25.     }  
  26.     // 初始化全部成员变量的构造器  
  27.     public Student(Integer studentNumber , String name)  
  28.     {  
  29.         this.studentNumber = studentNumber;  
  30.         this.name = name;  
  31.     }  
  32.   
  33.     // studentNumber的setter和getter方法  
  34.     public void setStudentNumber(Integer studentNumber)  
  35.     {  
  36.         this.studentNumber = studentNumber;  
  37.     }  
  38.     public Integer getStudentNumber()  
  39.     {  
  40.         return this.studentNumber;  
  41.     }  
  42.   
  43.     // name的setter和getter方法  
  44.     public void setName(String name)  
  45.     {  
  46.         this.name = name;  
  47.     }  
  48.     public String getName()  
  49.     {  
  50.         return this.name;  
  51.     }  
  52.   
  53.     // enrolments的setter和getter方法  
  54.     public void setEnrolments(Set<Enrolment> enrolments)  
  55.     {  
  56.         this.enrolments = enrolments;  
  57.     }  

此例就是通过@NamedNativeQuery定义了一个simpleQuery的SQL查询,因为此查询较简单,所以通过 @NamedNativeQuery的resultClass属性将结果集映射Student实体就可以了,这样该命名查询查询得到的结果应该是集合元素Student的List集合

下面方法即可执行上面命名的SQL查询

  1. public class NamedSQLTest  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         NamedSQLTest test = new NamedSQLTest();  
  6.            test.simpleQuery();  
  7.         HibernateUtil.sessionFactory.close();  
  8.     }  
  9.   
  10.     // 执行简单的命名SQL查询  
  11.     private void simpleQuery()  
  12.     {  
  13.         // 打开Session和事务  
  14.         Session session = HibernateUtil.currentSession();  
  15.         Transaction tx = session.beginTransaction();  
  16.         // 调用命名查询,直接返回结果  
  17.         List<Student> list = session.getNamedQuery("simpleQuery")  
  18.             .list();  
  19.         tx.commit();  
  20.         HibernateUtil.closeSession();  
  21.         // 遍历结果集  
  22.         for(Studentele : list)  
  23.         {  
  24.             // 每个集合元素是Student对象  
  25.             System.out.println(s.getName() + "\t");  
  26.         }  
  27.     }  
  28. }  

二:基于标量查询、实体查询的复杂查询

首先我们定义一个复杂的命名SQL查询

  1. // 定义一个命名SQL查询,其名称为queryTest  
  2. @NamedNativeQuery(name="queryTest"  
  3.     // 定义SQL语句  
  4.     , query="select s.*,e.*,c.* from student_inf s,enrolment_inf e,"  
  5.     + " course_inf c where s.student_id = e.student_id and"  
  6.     + " e.course_code = c.course_code and e.year=:targetYear"  
  7.     // 指定使用名为firstMapping的@SqlResultSetMapping完成结果映射  
  8.     , resultSetMapping = "firstMapping")  

此查询语句复杂,查询数据列较多,因此我们使用firstMapping结果映射来负责结果集的转换。这里使用的是名为firstMapping结果映射,下面是 firstMapping结果映射的定义:

  1. @SqlResultSetMapping(name="firstMapping"  
  2.             ,entities={@EntityResult(entityClass=Student.class),  
  3.                     @EntityResult(entityClass=Enrolment.class),  
  4.                     @EntityResult(entityClass=Course.class,fields=  
  5.                         {  
  6.                                 @FieldResult(name="id" , column="c.course_code"),  
  7.                                 @FieldResult(name="name" , column="c.name")  
  8.                             }  
  9.                       
  10.                             )}  
  11.           ,columns={@ColumnResult(name="s.name")}  
  12.     )  

可以看出我们通过@SqlResultSetMapping定义了一个 firstMapping结果映射,另外通过entities指定了三个@EntityResult注解,通过columns指定了一个@ColumnResult,这就说明该SQL查询包含了三个实体查询,一个标量查询。

以下方法可以执行上面的命名SQL查询:

  1. public class NamedSQLTest  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         NamedSQLTest test = new NamedSQLTest();  
  6.         test.query();  
  7.         HibernateUtil.sessionFactory.close();  
  8.     }  
  9.   
  10.   
  11.   
  12.     // 执行命名SQL查询  
  13.     private void query()  
  14.     {  
  15.         // 打开Session和事务  
  16.         Session session = HibernateUtil.currentSession();  
  17.         Transaction tx = session.beginTransaction();  
  18.         // 调用命名查询,直接返回结果  
  19.         List list = session.getNamedQuery("queryTest")  
  20.             .setInteger("targetYear" , 2005)  
  21.             .list();  
  22.         tx.commit();  
  23.         HibernateUtil.closeSession();  
  24.         // 遍历结果集  
  25.         for(Object ele : list)  
  26.         {  
  27.             // 每个集合元素是Student、Enrolment  
  28.             // 和stuName三个元素的数组  
  29.             Object[] objs = (Object[])ele;  
  30.             Student s = (Student)objs[0];  
  31.             Enrolment e = (Enrolment)objs[1];  
  32.             Course c = (Course)objs[2];  
  33.             String stuName = (String)objs[3];  
  34.             System.out.println(s.getName() + "\t"  
  35.                 + e.getYear() + "\t" + e.getSemester()  
  36.                 + "\t=" + e.getCourse().getName() + "=\t" + stuName);  
  37.         }  
  38.     }  
  39. }  

这里可以看出返回的结果集合,每一个集合元素都是几个实体所组成的数组,这里前三个数组元素正是我们定义的三个实体查询,第四个数组元素使我们定义的标量查询。

另外:当我们需要定义多个@NamedNativeQuery时,我们使用@NamedNativeQueries({})来管理,

    当我们需要定义多个@SqlResultSetMapping时,我们使用@SqlResultSetMappings({})管理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值