Hibernate(二)

1. 對象的狀態

代碼 java


public class StateTest extends HiberanteUtils{
	/**
	 * session.save方法把一個臨時狀態的對象轉化成持久化狀態的對象
	 */
	@Test
	public void testSavePerson(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = new Person();
		person.setPname("afds");
		person.setPsex("af");	
		session.save(person);
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * session.update方法能夠把一個對象的狀態變成持久化狀態
	 */
	@Test
	public void testUpdate(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person2 = new Person();//臨時狀態
		person2.setPid(1L);//臨時狀態
		session.update(person2);//持久化狀態
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * 當session.get方法獲得一個對象的時候,是不須要再執行 update語句,由於已是持久化狀態
	 * 當一個對象是一個持久化對象的時候,當進行提交的時候,hibernate內部會讓該對象和快照進行對比,若是同樣,則不發出update語句
	 * 若是不同,則發出update語句
	 */
	@Test
	public void testGet(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = (Person)session.get(Person.class, 1L);//持久化
		person.setPname("ttkjkjhg");
		
		//session.update(person);
		transaction.commit();
		session.close();
	}
	
	/**
	 * session.clear方法把全部的對象從session中清空
	 */
	@Test
	public void testClear(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = (Person)session.get(Person.class, 1L);
		person.setPname("asd");
		session.clear();//把session中全部的對象清空
		session.update(person);//把對象從脫管狀態轉化成持久化狀態
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * session.evict把一個對象從session中清空
	 */
	@Test
	public void testEvict(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = (Person)session.get(Person.class, 1L);
		person.setPname("asdsss");
		session.evict(person);//脫管狀態
		session.update(person);//把對象的狀態轉化成持久化狀態
		
		transaction.commit();
		session.close();
	}
	
	
	/**
	 * 一個對象是不是持久化對象是針對某一個session而言的
	 */
	@Test
	public void testSession(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = (Person)session.get(Person.class, 1L);
		person.setPname("asfd");
		transaction.commit();
		session.close();
		
		session =  sessionFactory.openSession();//94
		transaction =  session.beginTransaction();
		//person.setPname("aaa");//person對象對於94的session來講是一個臨時狀態的對象
		session.update(person);
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * 當執行transaction.commit的時候,hibernate內部會檢查session
	 *    一、若是一個對象爲臨時狀態的對象,則session不會管
	 *    二、若是一個對象是持久化狀態的對象,若是有ID值,而且和數據庫對應,
	 *    	 那麼先把該對象與快照進行對比,若是一致,則什麼都不作,若是不一致,則發出update語句
	 *    三、若是一個對象是持久化狀態的對象,若是沒有ID值,則會發出save語句
	 */
	@Test
	public void testMuplyOption(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = new Person();
		person.setPname("rrr1");
		person.setPsex("asdfasdf");
		
		Person person3 = new Person();
		person3.setPname("rrr2");
		person3.setPsex("asdfasdf");		
		session.save(person);
		
		Person person2 = (Person)session.get(Person.class, 18L);
		person2.setPname("asdfasdf");
		
		transaction.commit();//會檢查session中對象的狀態。若是是臨時對象,session根本無論
		//若是持久話對象的id有值,update.沒值,save()
		session.close();
	}
	
	
	@Test
	public void testMutiplyOption2(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Person person = new Person();
		person.setPname("haha1");
		person.setPsex("haha2");
		session.save(person); 
		transaction.commit();
		
		session.evict(person);
		session.close();
		
		session = sessionFactory.openSession();
		transaction = session.beginTransaction();
		session.update(person);
		session.clear();
		transaction.commit();
		session.close();
	}
}

2. 一對多的單項關聯

2.1. 數據庫表和實體類關係

2.2. Classes映射文件中cascade、inverse、外鍵的配置


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="cn.itcast.hiberate.sh.domain.Classes">
		<id name="cid" length="5" type="java.lang.Long">
			<generator class="increment"></generator>
		</id>
		<property name="cname" length="20" type="java.lang.String"></property>
		
		<property name="description" length="100" type="java.lang.String"></property>
		<!-- 
			set元素對應類中的set集合
			經過set元素使classes表與student表創建關聯
			   key是經過外鍵的形式讓兩張表創建關聯
			   one-to-many是經過類的形式讓兩個類創建關聯
			
			【cascade】 級聯
			   * save-update
			   	一、當保存班級的時候,對學生進行怎麼樣的操做
			   	     若是學生對象在數據庫中沒有對應的值,這個時候會執行save操做
			   	     若是學生對象在數據庫中有對應的值,這個時候會執行update操做
			   * delete:刪除班級的時候刪除學生
			   * all:save-update,delete
			
			【inverse】  維護關係
			   * true      不維護關係     
			   * false     維護關係
			   * default   false
			   inverse所在的映射文件類。Classes是否維護Classes與student之間的關係,若是不維護cid爲null			   
		 -->
		
		<!-- cascade表示,在對classes進行操做的時候對班級進行cascade中值的什麼操做 -->		
		<set name="students" cascade="all" inverse="true">
			<!-- key是用來描述外鍵-->
			<key>
				<column name="cid"></column>
			</key>
			<one-to-many class="cn.itcast.hiberate.sh.domain.Student"/>
		</set>
	</class>
</hibernate-mapping>




2.3. 代碼體現


package cn.itcast.hibernate.sh.test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.annotations.Type;
import org.junit.Test;

import cn.itcast.hiberate.sh.domain.Classes;
import cn.itcast.hiberate.sh.domain.Student;
import cn.itcast.hibernate.sh.utils.HiberanteUtils;

/**
 * 一、新建一個班級
 * 二、新建一個學生
 * 三、新建一個班級的時候同時新建一個學生
 * 四、已經存在一個班級,新建一個學生,創建學生與班級之間的關係
 * 五、已經存在一個學生,新建一個班級,把學生加入到該班級
 * 六、把一個學生從一個班級轉移到另外一個班級
 * 七、解析一個班級和一個學生之間的關係
 * 八、解除一個班級和一些學生之間的關係
 * 九、解除該班級和全部的學生之間的關係
 * 十、已經存在一個班級,已經存在一個學生,創建該班級與該學生之間的關係
 * 十一、已經存在一個班級,已經存在多個學生,創建多個學生與班級之間的關係
 * 十二、刪除學生
 * 1三、刪除班級
 *     刪除班級的時候同時刪除學生
 *     在刪除班級以前,解除班級和學生之間的關係
 * @author Think
 *
 */
public class OneToManySingleTest extends HiberanteUtils{
	@Test
	public void testSaveClasses(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setCname("傳智上海雲一期");
		classes.setDescription("很牛");
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	
	
	@Test
	public void testSaveStudent(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Student student = new Student();
		student.setSname("班長");
		student.setDescription("老牛:很牛");
		session.save(student);
		transaction.commit();
		session.close();
	}
	
	@Test
	public void testSaveClasses_Student(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = new Classes();
		classes.setCname("傳智上海雲二期:");
		classes.setDescription("很牛X");
		
		Student student = new Student();
		student.setSname("班長");
		student.setDescription("老牛:很牛X");
		
		session.save(student);
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	/**
	 * 在保存班級的時候,級聯保存學生
	 */
	@Test
	public void testSaveClasses_Cascade_Student_Save(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = new Classes();
		classes.setCname("傳智上海雲三期:");
		classes.setDescription("很牛XX");
		
		Student student = new Student();
		student.setSname("班長");
		student.setDescription("老牛:很牛XX");
		
		Set<Student> students = new HashSet<Student>();
		students.add(student);
		
		//創建classes與student之間的關聯
		classes.setStudents(students);
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	/**
	 * 在保存班級的時候,級聯更新學生
	 */
	@Test
	public void testSaveClasses_Cascade_Student_Update(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = new Classes();
		classes.setCname("傳智上海雲四期:");
		classes.setDescription("很牛XXX");
		
		Student student = (Student)session.get(Student.class, 1L);
		
		student.setSname("班祕");
		
		Set<Student> students = new HashSet<Student>();
		students.add(student);
		
		classes.setStudents(students);
	
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	/**
	 * 更新班級的同時保存學生
	 */
	@Test
	public void testUpdateClasses_Cascade_Student_Save(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = (Classes)session.get(Classes.class, 5L);
		
		Student student = new Student();
		student.setSname("班花");
		student.setDescription("稀有人物");
		
		classes.getStudents().add(student);//由於已經有班級了,因此先獲取班級的學生,再添加學生
		//由於classes是持久化對象,因此不用update()
		transaction.commit();
		session.close();
	}
	
	
	/**
	 * 更新班級的同時更新學生
	 */
	@Test
	public void testUpdateClasses_Cascade_Student_Update(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 5L);
		Set<Student> students = classes.getStudents();//爲cid爲5的班級的全部的學生
//		for(Student student:students){
//			student.setDescription("壓力山大");
//		}  快照
		transaction.commit();
		session.close();
	}
	
	/**
	 * 一個錯誤的演示---在classes映射文件中刪除了cascade="save-update"
	 * 保存班級的同時保存學生
	 * ------------------------------------
	 * 在客戶端試圖經過保存班級保存學生,可是因爲在配置文件中針對students沒有cascade屬性,沒有級聯,
	 * 因此致使classes中的student成爲臨時狀態的對象了,hibernate不容許這種狀況出現。
	 * 把session.save/update一個對象的操做爲顯示操做,級聯對象的操做爲隱式操做
	 */
	@Test
	public void testSaveClasses_Cascade_Student_Save_Error(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = new Classes();
		classes.setCname("傳智上海雲六期:");
		classes.setDescription("很牛XXXXXX");
		
		Student student = new Student();
		student.setSname("班長XXXXXX");
		student.setDescription("老牛:很牛XXXXXX");
		
		Set<Student> students = new HashSet<Student>();
		students.add(student);
		
		//創建classes與student之間的關聯
		classes.setStudents(students);
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	
	/**
	 * 【方式一】
	 * 已經存在一個班級,新建一個學生,創建學生與班級之間的關係
	 * ==============================================================
	 * 新創建一個學生,在學生表的cid自斷到處,添加這個學生班級的id,即創建了關係。
	 *    經過更新班級級聯保存學生  cascade起做用,負責:已經存在一個班級,新建一個學生
	 *    創建班級和學生之間的關係  inverse起做用,負責:創建學生與班級之間的關係
	 * ==============================================================
	 * 	用inverse屬性代替了外鍵,面向對象的思考方式。由於在student類中不能出現cid
	 * 	inverse用來維護兩個表之間的關係
	 */
	@Test
	public void testSaveStudent_R_1(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Student student = new Student();
		student.setSname("技術班長");
		student.setDescription("大神");
		Classes classes = (Classes)session.get(Classes.class, 1L);
		
		classes.getStudents().add(student);
		
		transaction.commit();
		session.close();
	}
	
	/**【方式二】
	 * 	Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
		Hibernate: select max(sid) from Student
		Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
		Hibernate: insert into Student (sname, description, sid) values (?, ?, ?)
		更新關係的操做
		Hibernate: update Student set cid=? where sid=?
	 */
	@Test
	public void testSaveStudent_R_2(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Student student = new Student();
		student.setSname("技術班長");
		student.setDescription("大神");
		Classes classes = (Classes)session.get(Classes.class, 1L);
		
		session.save(student);
		
		classes.getStudents().add(student);//只有創建了關係inverse才能起做用。若沒這行cid爲null
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * 已經存在一個學生,新建一個班級,把學生加入到該班級
	 */
	@Test
	public void testSaveClasses_R(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = new Classes();
		classes.setCname("老畢基礎增強班");
		classes.setDescription("必看,殺手鐗");
		
		Student student = (Student)session.get(Student.class, 2L);
		Set<Student> students = new HashSet<Student>();
		students.add(student);
		classes.setStudents(students);
		
		session.save(classes);
		transaction.commit();
		session.close();
	}
	
	/**
	 * 把一個學生從一個班級轉移到另外一個班級
	 * 	即:先解除班級和學生之間的關係,再創建學生和另一個班級之間的關係
	 * 	Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
		Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
		Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_ from Student student0_ where student0_.sid=?
		Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
		Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
		Hibernate: update Student set cid=null where cid=? and sid=? //解除
		Hibernate: update Student set cid=? where sid=? //創建
		簡單操做:直接把外鍵5變爲6就能夠完成
	 */
	@Test
	public void testTransformClass(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		//Classes classes5 = (Classes)session.get(Classes.class, 5L);
		Classes classes6 = (Classes)session.get(Classes.class, 6L);
		Student student = (Student)session.get(Student.class, 1L);
		//classes5.getStudents().remove(student); //只是移除了關係,並非刪除學生
		classes6.getStudents().add(student);//創建新關係
		
		transaction.commit();
		session.close();
	}
	
	/**
	 * 解除一個班級和一些學生之間的關係
	 */
	
	@Test
	public void testR_Some(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 1L);
		Set<Student> students = classes.getStudents();
//		for(Student student:students){
//			if(student.getSid().longValue()==6||student.getSid().longValue()==7){
//				students.remove(student);
//			}
//		}
		//set-->list
		List<Student> sList = new ArrayList<Student>(students);
		for(int i=0;i<sList.size();i++){
			if(sList.get(i).getSid().longValue()==6||sList.get(i).getSid().longValue()==7){
				sList.remove(sList.get(i));
				i--;
			}
		}
		
		students = new HashSet<Student>(sList);
		classes.setStudents(students);
		/**
		 * 加強for循環只能修改一次
		 *   一、用普通的for循環
		 *   二、新建一個set集合,把原來的set集合要保留的數據存放到新的set集合中
		 */
		transaction.commit();
		session.close();
	}
	
	/**解除班級一和全部學生之間的關係
	 * classes.setStudents(null);直接把班級針對student的集合設置爲null
	 */
	@Test
	public void testRealseAll(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = (Classes)session.get(Classes.class, 1L);
		
//方式一		Set<Student> students = classes.getStudents();
//		students.clear();   //爲什麼不用removeAll(Conllection c)
		//方式2
		classes.setStudents(null); 
		transaction.commit();
		session.close();
	}
	
	/**
	 * 刪除學生
	 */
	@Test
	public void testDeleteStudent(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Student student = (Student)session.get(Student.class, 8L);
		session.delete(student);
		
		transaction.commit();
		session.close();
	}
	
	
	/**
	 * 在刪除班級以前,解除班級和學生之間的關係
	 */
	@Test
	public void testDeleteClasses(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = (Classes)session.get(Classes.class, 5L);
		//classes.setStudents(null);//若是不維護關係。inverse=true
		session.delete(classes);//班級維護了關係,因此在刪除班級的時候,天然也解除了學生和班級的關係
		
		transaction.commit(); 
		session.close();
	}
	
	/**
	 * 級聯刪除班級5的同時刪除學生
	 */
	@Test
	public void testDeleteClasses_Cascade(){
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		
		Classes classes = (Classes)session.get(Classes.class, 5L);
		session.delete(classes);
		
		transaction.commit();
		session.close();
	}
}



2.4. 常見錯誤分析


3. hibernate基礎知識總結

一、hibernate的組成部分
    	持久化類
    	    實現對應的序列化接口
    	    必須有默認的構造函數
    	    持久化類的屬性不能使用關鍵字
    	    標示符
 		
	映射文件
 	    類型
		java類型和hibernate類型
 	    主鍵的產生器
		increment identity  assigned uuid
 	    id  prototype
 	    set集合
 		cascade  對象與對象之間的關係,和外鍵沒有關係
 		inverse  對象與外鍵之間的關係
  		
	配置文件
  	    數據庫的連接信息
  	    存放了映射文件的信息
  	    其餘信息:hibernate內部功能的信息
  		顯示sql語句:<property name="show_sql">true</property>
		生成表的:<property name="hbm2ddl.auto">update</property>


二、hibernate的流程
    Configuraction
      	加載了配置文件
		Configuration configuration = new Configuration();
		configuration.configure();
    SessionFactory(接口)
        配置文件的信息、映射文件的信息、持久化類的信息所有在SessionFactory
		特色:線程安全、單例
		SessionFactory sessionFactory = configuration.buildSessionFactory();
    Session(接口)
		Session session = sessionFactory.openSession();
        一、crud的操做都是由session完成的
        二、事務是由session開啓的
        三、兩個不一樣的session只能用各自的事務
        四、session決定了對象的狀態
			一個對象在session中,確定是持久化的
        五、建立完一個session,至關於打開了一個數據庫的連接
    Transaction
		Transaction transaction = session.beginTransaction();
		transaction.commit();
        一、事務默認不是自動提交的
			* jdbc的事務默認是自動提交的
        二、必須由session開啓
        三、必須和當前的session綁定(兩個session不可能共用一個事務)

三、對象的狀態的轉化

四、hibernate的原理:
     	根據客戶端的代碼,參照映射文件,生成sql語句,利用jdbc技術進行數據庫的操做
相關文章
相關標籤/搜索