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({})管理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章