1. 程式人生 > >Hibernate持久層框架使用【二】資料新增與修改

Hibernate持久層框架使用【二】資料新增與修改

Hibernate的資料新增與修改

新增資料:

hibernate提供了這幾種新增資料的方法,分別是:

save方法、saveOrUpdate方法、merge方法以及persist方法

在對資料庫進行操作時,過程是先開啟事務—操作資料庫—提交事務

上一篇部落格寫的hibernate測試類是這樣的

//載入配置檔案
		Configuration configuration = new Configuration().configure();
		
		//獲得服務註冊物件
		ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
				.applySettings(configuration.getProperties()).build();
		
		//定義一個SessionFactory物件
		SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		//SessionFactory sessionFactory = configuration.buildSessionFactory();
			
		//獲得Session
		Session session = sessionFactory.openSession();
		
		//開啟事務
		Transaction transaction = session.beginTransaction();
		
		//提交事務
		transaction.commit();
		
		//關閉資源
		session.close();
		sessionFactory.close();

如果每次操作資料都要寫這麼長一段程式碼來提交事務是非常不方便的,所以在此基礎上建個工具類來優化一下

MySessionFactory.class:

public class MySessionFactory {
	private SessionFactory sessionFactory = null;
	private Session session = null;
	private Transaction transaction = null;
	public Session getSession()
	{
		Configuration configuration = new Configuration().configure();
		sessionFactory = configuration.buildSessionFactory();
		session = sessionFactory.openSession();
		transaction = session.beginTransaction();
		return session;
	}
	
	public void commit()
	{
		transaction.commit();
	}
	
	public void close()
	{
		if(session!=null)
		session.close();
		if(sessionFactory!=null)
		sessionFactory.close();
	}
}

寫完工具類,再開始寫資料庫操作語句

save方法:

在save.class類下:

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
//		user.setId(1);
		user.setAge(1);
		user.setName("李白 ");
		
		session.save(user);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

執行後控制檯列印sql語句

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)

開啟資料庫,可以看到插入了一條資料,在儲存的時候,User物件的id是不用設定的,因為User表的id已經被設定為主鍵自增長了,即使對id賦值1000,在資料庫中插入的id還是為1

在hibernate中有瞬時狀態、持久化態、託管狀態的概念

瞬時狀態的物件可以理解為與資料庫無關的物件,例如當定義一個user物件

User user = new User();
 user.setAge(1);
user.setName("李 ");

這個user物件就是瞬時狀態,無論對user物件的資料如何更改,都不會影響到資料庫的資料,這個物件與session會話沒有任何關聯

但是如果呼叫save方法儲存物件後,user會從瞬時狀態轉為持久化態,對應資料表中的一條資料,再對user的資料進行更改時,會生成update語句對資料庫中的這條資料進行更改

例如save類這樣寫:

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(1);
		user.setName("李白 ");
		
		int key = (int)session.save(user);
		user.setName("杜甫");
		System.out.println("返回:"+key);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

呼叫save方法儲存物件時會返回這個物件的主鍵,這裡把主鍵打印出來測試一下。上面session呼叫了save方法並且生成了insert語句,但是這裡還沒有呼叫commit進行事務提交,如果在save方法下,對user的name進行更改,改為“杜甫”。再提交時會生成一條update語句來更改修改過的user物件,可以看到控制檯輸出了兩條控制語句

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
返回:6
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

從控制檯的sql語句可以看出,在呼叫save方法時馬上生成了insert語句並打印出來,儘管我們對user物件進行了修改,但是依然沒有立即列印update語句,而是先打出返回的主鍵,再列印update語句,說明update語句是在事務提交時才打印的,通過檢視資料庫,可以看到又插入了一條資料,name為更改過的“杜甫”

persist方法:

和save方法有幾點差別,這個方法無返回值,但是與save方法一樣,同樣將user物件轉為持久化態

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(1);
		user.setName("李白 ");
		
		session.persist(user);
		user.setName("杜甫");
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

由於persist沒有返回值,所以只能從user物件中拿到這條資料的id,列印一下,再檢視控制檯,確實列印除了insert語句,主鍵id和update語句

另一點不同的地方在於,save無論事務開不開啟,只要呼叫了save方法,首先生成了insert語句。而persist則必須在事務開啟的時候才生成insert語句(可以把MySessionFactory工具類中把transaction = session.beginTransaction()這一行註釋掉測試一下)

merge方法:

merge方法同樣可以用於插入資料,和上面兩個不一樣的地方在於它還可以修改資料,先看一下如何插入資料

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(1);
		user.setName("李白 ");
		
		User user2 = (User) session.merge(user);
		user2.setName("范仲淹");
		System.out.println("返回:"+user2.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

merge方法是有返回值的,返回這個資料物件,返回的這個資料物件才是與session關聯的持久態,如果直接在merge方法後修改user的值是不生效的,因為這個user僅是瞬時態,因此我們需要定義另一個user(即這裡的user2)來接收merge返回的物件,這時對user2進行修改操作才能生效,控制檯輸出sql語句,一條insert語句和一條update語句,測試完成,資料庫中又多了一條叫"范仲淹"的資料

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
返回:6
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

再來看一下merge方法的修改操作

如果想要修改資料庫中的資料但不想插入新的資料時,可以這樣寫

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setId(6);
		user.setAge(5);
		user.setName("李白");
		
		User user2 = (User) session.merge(user);
		//user2.setName("范仲淹");
		System.out.println("返回:"+user2.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

剛剛已經插入了一條id為6,age為1,name為范仲淹的資料

如果在user物件中將id設定為6,age為5,name為“李白”再呼叫merge方法時,由於已經存在了id為6的這一條資料,所以hibernate並不會插入新的資料,而是直接將這個id為6的資料查詢出來,再使用update語句將查詢出來的資料修改為age為5,name為“李白”的資料,下面是控制檯打印出來的sql語句

Hibernate: 
    select
        user0_.user_id as user_id1_0_0_,
        user0_.age as age2_0_0_,
        user0_.name as name3_0_0_ 
    from
        tb_user user0_ 
    where
        user0_.user_id=?
返回:6
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

當我們對這個返回的物件進行修改時,同樣生效。

saveOrUpdate方法:

saveOrUpdate方法是一個儲存資料或修改資料的方法,即如果資料表中沒有這條資料時則插入資料,又該條資料時則修改資料

例如:

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		//user.setId(6);
		user.setAge(5);
		user.setName("陸游");
		
		session.saveOrUpdate(user);
		//user.setAge(10);
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

這裡不設定user物件的id,資料庫自動插入了一條新的資料,控制檯輸出:

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
返回:9

說明儲存成功,這裡的user轉為持久態,在事務提交之前對user物件進行修改依然生成update語句並生效

但是如果我們在插入資料時把id設定為資料表中已有的id時,例如剛剛插入的id為6的資料

如下:

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setId(6);
		user.setAge(5);
		user.setName("駱賓王");
		
		session.saveOrUpdate(user);
		//user.setAge(10);
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

控制檯輸出update語句,修改成功

返回:6
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

再來看一下資料庫,發現剛剛插入的“陸游”已經被修改成“駱賓王”了

修改資料

update方法:

除了上面的saveOrUpdate方法和merge方法可以用來修改資料外,update也可以

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setId(6);
		user.setAge(5);
		user.setName("劉禹錫");
		
		session.update(user);
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}
返回:6
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

此時控制檯列印update語句修改了id為6的資料,修改成功

前面的方法能夠將瞬時態轉變為持久態,但是如果前面的user物件在提交事務前還需要其他用途,不想user物件依然為持久態時,可使用以下方法將被session管理的user物件從持久態中脫離

evict方法:

evict方法需要傳入一個Object引數,當你需要某一個物件脫離session管理時,可以將這個物件傳給該方法,驗證一下,這裡插入了兩條資料,再將兩條資料全部修改為“李白”,在修改之前加入evict方法使user脫離管理

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(5);
		user.setName("王安石");
		
		User user2 = new User();
		user2.setAge(5);
		user2.setName("王維");
		
		session.save(user);
		session.save(user2);
		
		session.evict(user);
//		session.clear();
		user.setName("李白");
		user2.setName("李白");
		
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}
Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
返回:5
Hibernate: 
    update
        tb_user 
    set
        age=?,
        name=? 
    where
        user_id=?

檢視控制檯看到列印除了兩條insert語句以及一條update語句,這條update語句就是沒有被取消託管的user2所做的修改,而user物件已經被取消託管了,再看一下資料表,發現數據表中插入了一條“王安石”(這是被取消託管了,沒改為“李白”)和一條“李白”(沒被取消託管的那個)

clear方法:

clear方法能夠將所有被session託管的持久化態物件全部脫離管理,例如下面程式碼插入兩條資料,並且將兩條資料都修改為”李白“,在修改之前,加入clear方法清空session管理的物件

public class save {
	public static void main(String[] args) {
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		User user = new User();
		user.setAge(5);
		user.setName("王安石");
		
		User user2 = new User();
		user2.setAge(5);
		user2.setName("王維");
		
		session.save(user);
		session.save(user2);
		
//		session.evict(user);
		session.clear();
		user.setName("李白");
		user2.setName("李白");
		
		System.out.println("返回:"+user.getId());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}
}

執行後可以看到控制檯只打印了兩條insert語句,而沒有列印update語句(如果將clear方法去掉,可以看到控制檯列印了兩條insert語句以及兩條update語句)

Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        tb_user
        (age, name) 
    values
        (?, ?)
返回:1