Configuration
Configuration接口的作用是對Hibernate進行配置,以及對它進行啓動,一般只創建一個實例。在Hibernate的啓
動過程中,Configuration類的實例首先定位映射文檔的位置,讀取這些配置,然後創建一個SessionFactory對象。
1.Configuration的創建方式
1.1 hibernate.properties配置文件
啓動hibernate時會去讀取properties作爲默認配置文件,該配置文件沒有提供添加Hibernate持久化類的方式,
因此使用hibernate.properties作爲配置文件時,必須調用Configuration對象的addAnnotatedClass()或
addPackage()方法添加持久化類。
Configuration cfg = new Configuration().configure().addAnnotatedClass(com.hibernate.demo.domain.News.class);
//StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
//sessionFactory = cfg.buildSessionFactory(serviceRegistry);
sessionFactory = cfg.buildSessionFactory();
1.2 hibernate.cfg.xml作爲配置文件
//hibernate的配置文件如果自定義的話就要指定文件名
//Configuration config = new Configuration().configure("myhibernate.cfg.xml");
//hibernate的配置文件名默認是hibernate.cfg.xml,可以不用指定
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
1.3 無配置文件
Configuration對象提供了下列方法進行持久化類和設置配置屬性:
1.Configuration.addAnnotatedClass(Class annotatedClass) :添加一個持久化類。
2.Configuration.addPackage(String packageName):添加指定包下面所有持久化類
3.Configuration.setProperties(Properties properties):通過Properties實例設置屬性。
4.Configuration.setProperty(String propertyName,String value):設置單個屬性。
// 實例化Configuration,不加載任何配置文件
Configuration conf = new Configuration()
// 通過addAnnotatedClass()方法添加持久化類
.addAnnotatedClass(org.crazyit.app.domain.News.class)
// 通過setProperty設置Hibernate的連接屬性。
.setProperty("hibernate.connection.driver_class"
, "com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url"
, "jdbc:mysql://localhost/hibernate")
.setProperty("hibernate.connection.username" , "root")
.setProperty("hibernate.connection.password" , "admin")
.setProperty("hibernate.c3p0.max_size" , "20")
.setProperty("hibernate.c3p0.min_size" , "1")
.setProperty("hibernate.c3p0.timeout" , "5000")
.setProperty("hibernate.c3p0.max_statements" , "100")
.setProperty("hibernate.c3p0.idle_test_period" , "3000")
.setProperty("hibernate.c3p0.acquire_increment" , "2")
.setProperty("hibernate.c3p0.validate" , "true")
.setProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQL5InnoDBDialect")
.setProperty("hibernate.hbm2ddl.auto" , "update");
//以Configuration實例創建SessionFactory實例
//StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
//SessionFactory sf = conf.buildSessionFactory(serviceRegistry);
SessionFactory sf = conf.buildSessionFactory();
2.Configuration的其他重要方法
2.1config() ; //通過指定參數來傳遞的方式讀取配置文件
File file = new File("c:\\Hibernate.xml");
Configuration config = new Configuration().config(file);
2.2 setProperties() //讀取properties文件
Properties properties = Porperties.load("a.properties");
Configuration configure = new Configuration().setProperties(properties);
2.3 addProperties()
SessionFactory
SessionFactory是用來創建session的工廠類,一般在一個項目初始化的時候構造一個實例(對應一個數據庫,
有多個數據庫時可以爲每個數據庫創建一個該實例),比如在一個公共靜態類中初始化一個SessionFactory的
readonly常量等等,它充當存儲數據源的代理,它是線程安全的,可以被多個線程調用,並且是重量級的,所以
只需要創建一個實例即可。
1 創建方式
try{
Configuration() config= new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
}catch(HibernateException e){
throw new RuntimeException(e.getMessage,e);
}
session
1.hibernate中的實例對象
存在三種中狀態:
1.1 自由狀態(瞬時狀態):對象被實例化,但是還沒有給對象的OID屬性賦值。
User user = new User(); //此時的user處於自由狀態
1.2 遊離狀態(託管狀態):實例化對象的OID屬性也被賦值。、
user.setId(1); //此時的user處於遊離狀態(還沒有進行持久化操作,數據庫中還沒有對應的數據)
1.3 持久狀態:僅與一個session相關聯。
session.save(user); //此時的user處於持久狀態 (數據庫中存在對應的數據)
2.session操作對象的區別
2.1 操作遊離對象
User user = new User();
user.setId(2);
user.setName("石破天");
user.setAge(25);
2.11 save()方法
session.save(user);
此時hibernate會執行一條sqlinsert語句,當數據庫中存在這條記錄時,就會拋異常。
2.12 saveOrUpdate()方法
session.saveOrUpdate(user);
當數據庫中沒有對應的數據時,hibernate會執行一條sqlinsert語句。當數據庫中有這條記錄時,
hibernate的髒檢查機制會自動檢查遊離對象的屬性值與數據庫中對應字段的值是否一致,如果
一致,則什麼都不用做,如果不一樣則執行sqlupdate語句。
例如:user中的 name="石破天",數據庫對應表中的對應字段 name="石破天",name的值一樣,
則什麼也不會做,否則就會執行更新語句。
2.13 persist()方法 //與save()方法差不多
2.14 update()方法
session.update(user);
執行一條sqlupdate語句,如果數據庫中不存在對應的記錄就會拋異常。
2.15 delete()方法
session.delete(user);
執行一條sqldelete語句,如果數據庫中不存在對應的記錄就會拋異常。
2.16 merge() 方法
這個方法基本和saveOrUpdate() 方法的用法相似。
2.17 lock() 方法
session.lock(user,LockMode.NONE); //必須在後面有一條setter 方法,不然Hibernate 什麼也不會做。
user.setAge(29);
當數據庫中存在這條記錄時,Hibernate 總會執行一條SQLUPDATE 語句;當數據庫中不存這條記錄時,
就會拋出異常。
2.18 replicate() 方法
session.replicate(user,ReplicationMode.EXCEPTION);
這個方法基本和save() 方法和 persist() 方法的用法相似。
2.2 session操作持久態對象
2.21 load() 方法
通過OID 從數據庫中抓取數據,並把數據加載到一個新實例對象上。
User user =(User) session.load(User.class, 1); // 此時的 user 處於持久狀態
調用這個方法時,當數據庫中存在這條記錄時,Hibernate 會執行一條 SQLSELECT 語句;當數據庫中沒
有這條記錄時,會拋出異常。
2.22 get() 方法
通過OID 從數據庫中抓取數據,並把數據加載到一個新實例對象上。
User user = (User) session.get(User.class, 1); // 此時的 user 處於持久狀態
調用這個方法時,當數據庫中存在這條記錄時,Hibernate 會執行一條 SQLSELECT 語句;當數據庫中沒
有這條記錄時,user = null。
2.23 save() 方法
User user = (User) session.load(User.class, 1);
user.setName("JOE");
session.save(user);
Hibernate的髒檢查機制會自動檢查對象的屬性(name)值與數據庫中對應的字段(name)值是否一樣。如果一
樣就什麼也不做;如果不一樣就執行SQLUPDTE 語句。
2.24 saveOrUpdate()方法
這時的saveOrUpdate() 和 save() 方法用法一樣。
2.25 persist() 方法
與 save() 方法一樣。
2.26 update() 方法
與 save() 方法一樣。
2.27 delete() 方法
session.delete(user);
Hibernate 執行一條 SQLDELETE 語句,這時 user 變爲遊離狀態。
2.28 merge() 方法:與 update() 方法一樣。
2.29 lock() 方法:與 update() 方法一樣。
2.210 session.lock(user,LockMode.NONE); //此時不必在後面有一條setter 方法。
2.211 replicate() 方法
與 update() 方法一樣。
session.replicate(user,ReplicationMode.EXCEPTION);
2.212 flush() 方法
與 update() 方法一樣。
User user = (User) session.load(User.class, 1);
user.setName("JOE");
session.flush();
2.213 refresh() 方法
User user = (User) session.get(User.class, 1);
user.setName("JOE");
session.flush();
session.refresh(user);
2.214 clear() 方法
清空Session 緩存
session.clear();
2.215 evcit() 方法:把持久對象從Session 緩存中移除。
session.evcit(user);
3 openSession()與getCurrentSession()
區別:1.getCurrentSession()創建的session會綁定到當前的線程中去,保證同一個線程使用的
session是同一個, 而採用openSession()則不會。
2.getCurrentSession()創建的session會在commit或rollback後自動關閉,採用openSession()
則不會。
3.使用getCurrentSession()需再核心配置文件中添加:
<property name="hibernate.current_session_context_class">thread</property>
4.openSession()得到得session可以在顯式開啓事務的環境中使用,也可以在不開啓事務的環
境中使用(只能獲取進行查詢,其他操作無效);getCurrentSession()必須在顯式開啓事務環
境中使用。
測試1:openSession在不開啓事務的情況下執行操作
Session session= SessionFactoryUtil.openSession();
(1):session.get(UserInfo.class,14L); //執行成功,得到數據
(2):session.delete(new UserInfo(16L)); //執行成功 但數據庫數據不變(符合邏輯)
session.close();
追溯了下源碼發現:
在不開啓事務的情況下,session得到數據庫連接是在執行查詢語句的時候從連接池中獲得。
Java代碼
private PreparedStatement getPreparedStatement(
final Connection conn,
String sql,
boolean scrollable,
final boolean useGetGeneratedKeys,
final String[] namedGeneratedKeys,
final ScrollMode scrollMode,
final boolean callable)
在調用這個方法時傳入了從連接池中拿到的連接。
在執行完數據操作後調用
afterOperation(boolean success);
發現是非事務型的session直接調用
connectionManager.aggressiveRelease();
釋放連接。
測試2:getCurrentSession()在不開啓事務的情況下執行操作
Session session= SessionFactoryUtil.getCurrentSession();
(1):session.get(UserInfo.class,14L); //拋出異常get is not valid without active transaction
(2):session.delete(new UserInfo(16L));// 拋出異常get is not valid without active transaction
//session.close(); //線程綁定session會自動關閉
說明: 線程綁定session必須開啓事務,此時的session已經加載了攔截器,在執行數據操作時必須在活動的事務範圍中。
測試3:openSession在開啓事務的情況下執行操作
Session session= SessionFactoryUtil.openSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //執行成功,得到數據
(2):session.delete(new UserInfo(16L)); //執行成功
session.getTransaction().commit();
session.close(); //如若配置hibernate.transaction.auto_close_session=true可省去
分析:
(a):session.getTransaction().begin()-->Transaction result = getTransaction()
-->result.begin()-->jdbcContext.connection()
{
if ( owner.isClosed() ) {
throw new SessionException( "Session is closed" );
}
return connectionManager.getConnection();
}
見到connectionManager有點熟悉了吧,這就是管理數據庫連接的連接池.
(b):session.getTransaction().commit()-->connectionManager.aggressiveRelease() 釋放連接。
此時的數據庫連接是在準備開啓事務的時獲得,事務提交的時候釋放連接。
測試4:getCurrentSession()在開啓事務的情況下執行操作
Session session= SessionFactoryUtil.getCurrentSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //執行成功
(2):session.delete(new UserInfo(16L)); //執行成功
session.getTransaction().commit();
說明: 線程綁定session已經加載了攔截器,提交的時候釋放連接關閉session。
5.openSession()是否顯式開啓事務決定了session得到連接的時機不同。不開啓事務的情況下數
據庫連接是在創建 Statement時獲得。因此在配置二級緩存的情況get()對象時,如果二級緩存
中有需要的對象時,不會佔用數據庫連接。相反開啓事務的情況下,無論二級緩存中是否有對
象,都會佔用數據庫連接。
6.this.getsession和this.getHibernateTemplate().getSessionFactory().getCurrentSession()/OpenSession
這兩者都是在hibernate與Spring整合時,dao繼承的HibernateDaoSupport,這樣的確能夠提高開發效率 ,
但是不夠靈活,而且使DAO層依賴於spring的api,增加了耦合。但是不考慮複用的話還可以。
this.getsession:父類的方法,使用spring管理hibernate的SessionFactory的時候,這個方法會從session
池中拿出一session.這樣做有可能有問題,就是超session池連接數的時候,spring無法自動關閉session。
不推薦使用。
其二者: 從spring管理的sessionFactory中創建一個綁定線程的session.spring會根據該線程的執行情況
來自動判斷是關閉session還是延遲關閉。這樣做可以避免手動的管理事務,同時一個線程最多開啓和關
閉一次session又可以提高程序的性能。 極力推薦使用這種方法。
其三者:此session不是線程綁定的。當執行完一個實務的時候自動關閉session.這種方法不用手動管理實
務,但是同一個線程多次的開啓和關閉session,浪費系統資源和影響執行效率,正常情況下還是不要用了。