1. 程式人生 > >Hibernate註解開發

Hibernate註解開發

Hibernate開發步驟

1.匯入Hibernate開發包中lib資料夾中required下的所有jar包

2.在src根目錄建立hibernate主配置檔案,hibernate.cfg.xml,cfg:configuration配置。

主配置檔案如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--匯入標籤庫:在Hibernate核心開發包中hibernate-configuration-3.0.dtd中-->
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<!-- 配置session-factory:要配置的位置在:    
	    hibernate解壓縮後的檔案/project/etc/hibernate.properties -->
	<session-factory>
		<!-- 資料庫連線引數 -->
		<!-- 使用property標籤對SessionFactory屬性進行配置 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 連線本地mysql可以省略地址 -->
		<property name="hibernate.connection.url">jdbc:mysql:///servletdb</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">1234</property>
		<!--配置currentSession:當前執行緒對應session-->
		<propertyname="hibernate.current_session_context_class">thread</property>  
		<!-- hibernate自動生成sql,將sql展示出來 -->
		<property name="show_sql">true</property>
		<!-- 對sql格式化輸出,將sql變美觀 -->
		<property name="hibernate.format_sql">true</property>
		<!-- 配置hibernate方言:hibernate.dialect
		    因為Hibernate無需編寫sql,但其底層需要把程式碼翻譯成sql;方言也就是告知hibernate以何種sql語句進行翻譯-->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		
		<!-- 配置hibernate對映檔案地址,對映檔案是實體類和資料庫表中對應的表的配置。 -->
		<mapping resource="entity/User.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

hibernate中的session相當於Connection,一個Session表示和資料庫的一次會話。 Sessionfactory:建立session的一個工廠類,相當於DriverManager

3.編寫實體類

4.編寫實體對映檔案:描述表和實體類之間的對映關係

一個表對應一個Java類,hbm:hibernate mapping 命名:類名.hbm.xml 位置:和實體類同包

<?xml version="1.0" encoding="UTF-8"?>
<!--匯入標籤庫-->
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<!-- 配置User類和t_user之間的對映關係
		name:全限定名 -->
	<class name="entity.User" table="t_user">
		<!-- 配置欄位名和屬性名之間的對映關係
			先配置主鍵
			name:屬性名
			column:列名 -->
		<id name="userId" column="user_id">
			<!-- generator:配置主鍵生成策略
				identity:自增mysql
				sequence:序列oracle/DB2
				uuid:32位全球唯一字串
				
				increment:自增,不建議使用
				native:由hibernate生成主鍵,不建議使用
				assigned:由程式生成主鍵
				 -->
			<generator class="identity"/>
			
		</id>
		<!-- 使用property對普通列配置 -->
		<property name="userName" column="user_name"/>
		<property name="password" column="password"/>
		<property name="age" column="age"/>
	</class>
</hibernate-mapping>

5.在hibernate主配置檔案中新增對映檔案路徑

6.編寫程式碼

Hibernate物件狀態:

三態: 初始態(Virgin):剛new出的物件 User user = new User(); 初始態物件和hibernate無關聯

持久態:呼叫hibernate save() update() load() get() Query物件的方法 等API時,物件會由初始態---->持久態 持久態的物件會被session進行管理,也就是和資料庫建立了直接關聯

遊離態(處理後的狀態):失去了session管理的物件 注意: 1.遊離態物件仍然存在,等待被GC(Garbage Collection)垃圾回收執行緒回收 2.遊離態物件有OID,主鍵值 3.遊離態物件可以重新回到持久態 saveOrUpdate(Object)

Hibernate簡單API

public class TestCRUD {

	private SessionFactory sf;
	
	@Before
	public void testSessionFactory(){
		//1.載入hibernate.cfg.xml
		//預設載入src下根目錄下的hibernate.cfg.xml
		//為一個Configuration物件
		Configuration cfg = new Configuration().configure();
		//2.通過Configuration建立SessionFactory
		sf = cfg.buildSessionFactory();
	}
	
	@Test
	public void testAdd(){
		//2.通過SessionFactory獲取Session
		Session session = sf.openSession();
		//3.開啟事務,hibernate預設不會自動提交事務
		Transaction tx = session.beginTransaction();
		//4.呼叫hibernateAPI完成CRUD
		User user = new User();
		user.setUserName("ss");
		user.setPassword("ss");
		user.setAge(10);
		//session.save(Object):把該Java物件入庫
		session.save(user);
		//5.操縱完畢後提交事務
		tx.commit();
		//6.關閉Session
		session.close();
	}

	@Test
	public void testDelete(){
		//hibernate預設按主鍵刪除,物件主鍵屬性必須有值
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();
		User user = new User();
		user.setUserId(5);
		//session.delete(Object):刪除該物件對應的資料庫記錄
		session.delete(user);
		tx.commit();
		session.close();
	}
	
	@Test
	public void testQuery(){
		//按主鍵查詢:get/load
		//使用openSession查詢可以不開啟事務
		Session session = sf.openSession();
		//session.get(類物件,主鍵值)
		User user = session.load(User.class, 11);
		System.out.println(user);
		session.close();
	}
	
	@Test
	public void testUpdate(){
		//先查後改
		Session session = sf.openSession();
		Transaction tx = session.beginTransaction();
		//查出一個User
		User user = session.load(User.class, 11);
		user.setUserName("GayP");
//		session.update(user);
		tx.commit();
		session.close();
	}
	
}
session.get/load(類物件,主鍵值)
get/load的區別:
1.get是立即載入,使用get會立刻向資料庫傳送sql語句
 load是延遲載入,在呼叫物件的方法或者屬性前不傳送sql,當呼叫物件的方法或者屬性時才傳送sql
2.get不存在的主鍵,返回值為null
  load會丟擲ObjectNotFoundException

複雜查詢: 1.按ID查:get/load 2.使用HQL進行查詢 Hibernate Query Language:HQL HQL是一種類SQL語句: 1.HQL沒有表的概念,表名統一替換為類名 2.HQL沒有列的概念,列名統一替換屬性名 3.無select * from 類名: from 類名 查詢所有列 一個應用一般只需要一個SessionFactory 封裝HibernateUtil工具類實現SessionFactory單例

先實現一個HibernateUtil類,並測試Query物件

public class HibernateUtil {
	
	private static Configuration cfg;
	private static SessionFactory sf;
	//事務寫成共有的,外界需要用
	public static Transaction tx;
	
	static{
		cfg = new Configuration().configure();
		sf = cfg.buildSessionFactory();
	}
	/**
	 * 獲取Session物件
	 */
	public static Session getSession(){
		Session session = sf.openSession();
		tx = session.beginTransaction();
		return session;
	}
}


public class TestQuery {
	
	@Test
	public void testAllUser(){
		Session session = HibernateUtil.getSession();
		//1.編寫HQL
		String hql = "from User where userName =:username"
				+ " and password =:password";
		//2.通過session建立Query物件並傳入HQL語句
		Query query = session.createQuery(hql);
		//3.呼叫Query物件的API完成查詢
		query.setParameter("username", "GayP");
		query.setParameter("password", "ooxx1");
		List<User> users =  query.list();
		System.out.println(users==null);
		System.out.println(users.isEmpty());
		for (User user : users) {
			System.out.println(user);
			System.out.println("-----------");
		}
		HibernateUtil.tx.commit();
		session.close();
	}
	
	@Test
	public void testFindAllUser2(){
		Session session = HibernateUtil.getSession();
		//1.編寫HQL
		String hql = "from User";
		//2.通過HQL建立Query物件
		Query query = session.createQuery(hql);
		Iterator<User> it = query.iterate();
		while(it.hasNext()){
			User user = it.next();
			System.out.println(user);
			System.out.println("-----------");
		}
	}
	
	@Test
	public void testQueryUserByName(){
		Session session = HibernateUtil.getSession();
		String hql = "from User where userName = ?";
		Query query = session.createQuery(hql);
		//給佔位符賦值
		//注意HQL佔位符從0開頭
		query.setParameter(0, "GayP");
		//注意:返回值為單行記錄才能使用uniqueResult()
		//uniqueResult():Object
		User user = (User) query.uniqueResult();
		System.out.println(user);
		HibernateUtil.tx.commit();
		session.close();
	}
	
	@Test
	public void testQueryUserByName2(){
		Session session = HibernateUtil.getSession();
		String hql = "from User where userName =:username"
				+ " and password =:password";
		Query query = session.createQuery(hql);
		//給佔位符賦值
		query.setParameter("username", "GayP");
		query.setParameter("password", "ooxx");
		//注意:返回值為單行記錄才能使用uniqueResult()
		//uniqueResult():Object
		User user = (User) query.uniqueResult();
		System.out.println(user);
		HibernateUtil.tx.commit();
		session.close();
	}
	
	
	@Test
	public void testQueryUserByName3(){
		Session session = HibernateUtil.getSession();
		String hql = "from User where userName =:username"
				+ " and password =:password";
		Query query = session.createQuery(hql);
		//把引數封裝為一個map:
		//key:引數名
		//value:引數值
		Map<String, Object> parameters =
				new HashMap<String,Object>();
		parameters.put("username", "GayP");
		parameters.put("password", "ooxx");
		//給佔位符賦值
		query.setProperties(parameters);
		//注意:返回值為單行記錄才能使用uniqueResult()
		//uniqueResult():Object
		User user = (User) query.uniqueResult();
		System.out.println(user);
		HibernateUtil.tx.commit();
		session.close();
	}
	
	@Test
	public void testQueryUserByName4(){
		Session session = HibernateUtil.getSession();
		String hql = "from User where userName =:username"
				+ " and password =:password";
		Query query = session.createQuery(hql);
		//把引數封裝為一個JavaBean:
		UserQueryBean qb = new UserQueryBean();
		qb.setUsername("GayP");
		qb.setPassword("ooxx");
		//給佔位符賦值
		query.setProperties(qb);
		//注意:返回值為單行記錄才能使用uniqueResult()
		//uniqueResult():Object
		User user = (User) query.uniqueResult();
		System.out.println(user);
		HibernateUtil.tx.commit();
		session.close();
	}
	
	//投影查詢1:封裝為JavaBean
	@Test
	public void testHeadHard1(){
		Session session = HibernateUtil.getSession();
		String hql = "select new entity.User(userName,password)"
				+ " from User";
		List<User> users = session.createQuery(hql).list();
		for (User user : users) {
			System.out.println(user);
			System.out.println("----------");
		}
		HibernateUtil.tx.commit();
		session.close();
	}
	
	@Test
	public void testHeadHard2(){
		Session session = HibernateUtil.getSession();
		String hql = "select new Map(userName,password) from User";
		//查詢一行結果對應一個Map
		//多個Map的集合就是一個List
		List<Map<String, Object>> result = 
				session.createQuery(hql).list();
		for (Map<String, Object> map : result) {
			//遍歷Map
			for (Entry<String, Object> entry : map.entrySet()) {
				System.out.println(entry.getKey() + ":" 
						+ entry.getValue());
			}
			//內層迴圈走完,一行遍歷結束
			System.out.println("-------------");
		}
		HibernateUtil.tx.commit();
		session.close();
	}
	
	
}

如何給hql中的佔位符賦值: 引數較少時 1.query.setParameter(“引數名”,引數值);

引數較多時 2.把引數封裝成Map query.setProperties(map); 3.把引數封裝為一個JavaBean query.setProperties(Java物件);

投影查詢

查詢部分列: 1.select new entity.User(userName,password) from User 把查詢結果封裝成JavaBean 注意:該類中必須有相應的構造 2.select new Map(屬性名1,屬性名2…) from 類名 把查詢結果封裝成Map Map的key是下標,value就是屬性值 3.hql:select 屬性名1,屬性名2… from 類名 使用Object[]封裝查詢結果: 一行記錄對應一個Object[],多行記錄對應一個List<Object[]> 注意:只能封裝查詢結果,無法查詢屬性名或下標。

openSession和getCurrentSession的區別

1.openSession無需配置getCurrentSession需要配置 在主配置檔案中新增 <propertyname=“hibernate.current_session_context_class”>thread current:當前執行緒 一個事務對應一個執行緒 當前事務 CurrentSession:執行緒繫結session 1.當前事務對應的session 2.一個事務對應一個session 事務結束:commiy rollback session物件自動銷燬(不需要再呼叫session.close();方法) 3.CurrentSession在事務結束後,無需也不能close該session 注意: CurrentSession是和事務繫結的,沒有事務也就沒有session 獲取CurrentSession必須開啟事務 openSession無需開啟事務 4.CurrentSession是執行緒安全的 openSession是執行緒非安全的,有可能產生執行緒併發問題

載入方式

一.延遲載入的概念   
當Hibernate從資料庫中載入某個物件時,不載入關聯的物件,
只是生成了代理物件,獲取使用session中的load的方法(在沒有
改變lazy屬性為false的情況下)獲取到的也是代理物件,所以在上
面這幾種場景下就是延遲載入。

二.立即載入的概念     
當Hibernate從資料庫中載入某個物件時,載入關聯的物件,
生成的實際物件,獲取使用session中的get的方法獲取到的是實際物件。  

三.為什麼要使用延遲載入     
延遲載入策略能避免載入應用程式不需要訪問的關聯物件,以提高
應用程式的效能。    

四.立即載入的缺點    Hibernate在查詢某個物件時,立即查詢與之關聯的物件,我們
可以看出這種載入策略存在兩大不足 
1.select的語句數目太多,需要頻繁的訪問資料庫,會影響查詢的效能。    
2.在應用程式只需要訪問要的物件,而不需要訪問與他關聯的物件
的場景下,載入與之關聯的物件完全是多餘的操作,這些多餘的操
作是會佔記憶體,這就造成了記憶體空間的浪費。    

Hibernate在物件-關係對映問價中配置載入策略(以檔案形式對映) I.類級別: 元素中lazy屬性的可選值為true(延遲載入)和false(立即載入); 元素中的lazy屬性的預設值為true II.一對多關聯級別: 元素中的lazy屬性的可選值為:true(延遲載入),extra(增強延遲載入)和false(立即載入); 元素中的lazy屬性的預設值為true III.多對一關聯級別: 元素中lazy屬性的可選值為:proxy(延遲載入),no-proxy(無代理延遲載入)和false(立即載入) 元素中的lazy屬性的預設值為proxy