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()作用,将结果集转换为标量查询,有几个@ColumnResult注解就相当于调用几次SQLQuery的addScalar()方法。

同样@EntityResult注解作用类似于SQLQuery对象的addEntity()作用,将结果集转换为标量查询,有几个@EntityResult注解就相当于调用几次SQLQuery的addEntity()方法。

下面是实例:

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


// 定义一个命名SQL查询,其名称为simpleQuery
@NamedNativeQuery(name="simpleQuery"
	// 指定命名SQL查询对应的SQL语句
	, query="select s.student_id , s.name from student_inf s"
	// 指定将查询结果转换为Student实体
	, resultClass=Student.class)
@Entity
@Table(name="student_inf")
public class Student
{
	// 代表学生学号的成员变量,将作为标识属性
	@Id @Column(name="student_id")
	private Integer studentNumber;
	// 代表学生姓名的成员变量
	private String name;
	// 该学生的所有选课记录对应的关联实体
	@OneToMany(targetEntity=Enrolment.class
		, mappedBy="student" , cascade=CascadeType.REMOVE)
	private Set<Enrolment> enrolments
		= new HashSet<>();

	// 无参数的构造器
	public Student()
	{
	}
	// 初始化全部成员变量的构造器
	public Student(Integer studentNumber , String name)
	{
		this.studentNumber = studentNumber;
		this.name = name;
	}

	// studentNumber的setter和getter方法
	public void setStudentNumber(Integer studentNumber)
	{
		this.studentNumber = studentNumber;
	}
	public Integer getStudentNumber()
	{
		return this.studentNumber;
	}

	// name的setter和getter方法
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return this.name;
	}

	// enrolments的setter和getter方法
	public void setEnrolments(Set<Enrolment> enrolments)
	{
		this.enrolments = enrolments;
	}

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

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

public class NamedSQLTest
{
	public static void main(String[] args)
	{
		NamedSQLTest test = new NamedSQLTest();
	       test.simpleQuery();
		HibernateUtil.sessionFactory.close();
	}

	// 执行简单的命名SQL查询
	private void simpleQuery()
	{
		// 打开Session和事务
		Session session = HibernateUtil.currentSession();
		Transaction tx = session.beginTransaction();
		// 调用命名查询,直接返回结果
		List list = session.getNamedQuery("simpleQuery")
			.list();
		tx.commit();
		HibernateUtil.closeSession();
		// 遍历结果集
		for(Object ele : list)
		{
			// 每个集合元素是Student对象
			Student s = (Student)ele;
			System.out.println(s.getName() + "\t");
		}
	}
}

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

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

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

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

@SqlResultSetMapping(name="firstMapping"
			,entities={@EntityResult(entityClass=Student.class),
					@EntityResult(entityClass=Enrolment.class),
					@EntityResult(entityClass=Course.class,fields=
						{
								@FieldResult(name="id" , column="c.course_code"),
								@FieldResult(name="name" , column="c.name")
							}
					
							)}
	      ,columns={@ColumnResult(name="s.name" ,type=String.class)}
	)

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

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

public class NamedSQLTest
{
	public static void main(String[] args)
	{
		NamedSQLTest test = new NamedSQLTest();
		test.query();
		HibernateUtil.sessionFactory.close();
	}



	// 执行命名SQL查询
	private void query()
	{
		// 打开Session和事务
		Session session = HibernateUtil.currentSession();
		Transaction tx = session.beginTransaction();
		// 调用命名查询,直接返回结果
		List list = session.getNamedQuery("queryTest")
			.setInteger("targetYear" , 2005)
			.list();
		tx.commit();
		HibernateUtil.closeSession();
		// 遍历结果集
		for(Object ele : list)
		{
			// 每个集合元素是Student、Enrolment
			// 和stuName三个元素的数组
			Object[] objs = (Object[])ele;
			Student s = (Student)objs[0];
			Enrolment e = (Enrolment)objs[1];
			Course c = (Course)objs[2];
			String stuName = (String)objs[3];
			System.out.println(s.getName() + "\t"
				+ e.getYear() + "\t" + e.getSemester()
				+ "\t=" + e.getCourse().getName() + "=\t" + stuName);
		}
	}
}

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

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

    当我们需要定义多个@SqlResultSetMapping时,我们使用@SqlResultSetMappings({})管理

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值