一. 單例工廠類
因爲我們每一個測試方法都需要讀取配置文件,創建工程,創建session,所以我們可以寫這樣子的一個工具類來做這些操作:
public class HibernateUtil {
private static Configuration cfg = null;
private static SessionFactory factory = null;
static {
if (cfg == null) {
cfg = new Configuration().configure();
}
if (factory == null) {
factory = cfg.buildSessionFactory();
}
}
public static SessionFactory getSessionFactory() {
return factory;
}
public static Session getSession() {
return factory.openSession();
}
public static void closeSession(Session session) {
if (session != null) {
session.close();
}
}
<span style="font-family:Microsoft YaHei;">}</span>
這樣就大大簡化了我們的代碼。二. 持久化對象的三種狀態
1. 瞬時對象
使用new操作符初始化的對象不是立刻就持久的,是瞬時的。
2. 持久化對象
在使用sql的insert、update、delete語句吧內存中的對象同步到數據庫中,即當持久對象修改數據的時候,會自動同步到數據庫中。
3. 離線狀態
在session關閉之後就處於離線狀態,不能同步數據到數據庫中了,可以使用sql的insert、update、delete語句重新實現持久化,同步數據。
三. Session的常用方法
1. save和saveOrUpdate的區別
我們這樣子修改添加的方法:
public void testAdd() {
User user = new User();
user.setUsername("張三");
user.setSex("男");
user.setAge(27);
user.setBirthday(new Date());
user.setSalary(100.5);
user.setId(2);
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
// 添加User實體對象
session.save(user);
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
給User指定了id,但是發現查看數據庫,還是遞增的向後排,並沒有理我們的設定的id爲2,相當於執行了save方法。將save改成saveOrUpdate方法,執行發現將id爲2的內容修改成了我們設置的User,相當於執行了update方法;如果setId傳了一個數據庫不存在的值,那麼它執行的又變回了save方法。
還有一點需要注意的是不論是save方法還是saveOrUpdate方法對持久對象不起作用。
/**
* save和saveOrUpdate方法對持久對象都不起作用
*/
public void testAdd2() {
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
// 添加User實體對象
User user = (User) session.get(User.class, 2);
session.save(user);
// session.saveOrUpdate(user);
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
執行發現,並沒有添加新的數據出來,當修改user的數據時,是持久對象發生了同步update方法,並不是save或者saveOrUpdate起了作用。2. persist和save以及merge和update的區別
persist和save都可以把對象存進數據庫,沒有什麼區別。
接下來我們看這個方法:
public void testUpdate() {
User user = new User();
user.setUsername("陳小春");
user.setSex("男");
user.setAge(40);
user.setBirthday(new Date());
user.setSalary(110.5);
user.setId(3);
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
User u = (User) session.get(User.class, 3);
session.update(user);
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
執行後會發現報錯了,說有兩個相同id的實體,這裏修改成merge而不是update的時就會正常執行。實際上執行merge方法時,會先將merge參數中user的全部屬性賦值給u對象,然後更新u對象。3. lock(已淘汰)和update方法的區別
lock是原來爲了將對象重新持久化而使用的一個方法,現在已經廢棄了,使用update代替了。
4. save、update、get、delete方法的執行順序和flush方法
在一個session的執行過程中,不管save、update、get和delete寫在程序的哪裏,他們的執行順序都是先get,然後save,然後update最後delete,如果想要先執行某個方法,那麼需要在這個方法之後調用flush方法即可:
public void testOrder() {
User user = new User();
user.setUsername("第一個");
user.setSex("男");
user.setAge(27);
user.setBirthday(new Date());
user.setSalary(100.5);
user.setId(2);
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
User u = (User) session.get(User.class, 10);
u.setUsername("更新的第10條");
session.delete(session.get(User.class, 7));
session.delete(session.get(User.class, 8));
session.flush();
// 添加User實體對象
session.save(user);
user = new User();
user.setUsername("新的一個");
user.setAge(17);
user.setBirthday(new Date());
user.setSalary(294.4);
user.setSex("女");
session.save(user);
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
5. clear及evict方法
public void testclear() {
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
Query query = session
.createQuery("from com.thr.hibernate.entity.User");
List<User> users = query.list();
// session.clear();
for (User user : users) {
user.setUsername(user.getUsername() + "new");
}
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
當執行了query.list方法後,查詢出來的集合已經放在了緩存中,可以持久化更新,但是如果執行了session.clear()方法後,那麼緩存就都清空了,後面的users並不持久化,無法更新了。修改代碼:
int i = 0;
for (User user : users) {
i++;
if (i == 3) {
session.evict(user);
}
user.setUsername(user.getUsername() + "new");
}
意思是當執行到第3個元素的時候,將其從緩存中剔除掉,那麼第3個元素就不會執行更新語句了。6. get和load方法的區別
public void test() {
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
//User user = (User) session.get(User.class, 10);
User user = (User) session.load(User.class, 10);
System.out.println(user.getUsername());
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
使用get方法的時候在執行get方法後,立刻就進行了查詢操作;但使用load方法會延時加載,在需要使用到user的時候纔會執行查詢的操作。是否開啓懶加載還可以在hibernate的配置文件中通過配置lazy="false"來設置:<span style="white-space:pre"> </span><class name="com.thr.hibernate.entity.User" table="T_USER" lazy="true">
當查詢不到結果的時候get方法會返回null,而load方法會報異常。7. list和iterator方法
public void testIterator() {
Session session = HibernateUtil.getSession();
// 創建及開啓事務對象
Transaction trans = null;
try {
trans = session.beginTransaction();
Query query = session
.createQuery("from com.thr.hibernate.entity.User");
// List<User> users = query.list();
// for (User user : users) {
// System.out.println(user);
// }
Iterator<User> it = query.iterate();
while (it.hasNext()) {
System.out.println(it.next());
}
it = query.iterate();
while (it.hasNext()) {
System.out.println(it.next());
}
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
使用註釋中的list方法是執行了一條查詢,直接查出了所有的數據,如果第二次執行list還是會查詢所有的數據;而使用iterator第一次查詢是查出了所有的id,然後使用id去查詢每一條數據,如果有第二次的話,還是去查詢所有的id,如果發現和第一次id有一樣的,會直接使用第一次的數據,沒有多餘的操作。