一、創建SessionFactory的兩種方式:(將下面其中一種封裝成getSessionFactory方法)
1、通過進行創建Configuration:
//創建配置對象
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");
//創建session工廠
return cfg.buildSessionFactory();
2、通過服務註冊類實現
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
SessionFactory sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
二、創建一個Main測試類:
public static void main(String[] args) {
//獲取session工廠
SessionFactory factory = getSessionFactory();
//打開一個新的session
Session session=factory.openSession();
//開始事務
Transaction t=session.beginTransaction();
//這裏寫操作數據庫的代碼(下面的測試代碼均在此處寫)
//提交事務
t.commit();
//關閉session
session.close();
//關閉session工廠
factory.close();
}
三、測試保存或更新api
Integer index = (Integer)session.save(employee);//返回數據庫中的主鍵Id
session.persist(employee);//沒有返回值
Object o = session.merge(employee);//返回整個對象
session.saveOrUpdate(employee);//沒有返回值,如果有主鍵那麼更新,沒有則插入新紀錄
注意上述的各種方法都會將對象存入到一級緩存session中(其實就是一個Map結構"EntityKey[domain.Employee#112]" -> obj,在變量persistenceContext中),此時的對象都是持久態的
四、各種查詢
Employee employee = session.find(Employee.class,101);//直接跟進id查詢
employee.setLastName("xtz");持久化的對象在提交事務後會主動把結果更新的到數據庫
Employee employee = session.load(Employee.class,101);//通過id查詢,通過懶加載的方式 employee.setLastName("jeff");//使用到這個對象的時候,才發送查詢sql,同樣的,在關閉事務也會刷線到數據庫中
HQL Query<Employee> query = session.createQuery("from domain.Employee");//創建查詢,可以加where order by 等,但是不能加limit
query.setMaxResults(10);//記錄數,用於分頁
query.setFirstResult(11);//記錄開始的下標,從0開始,用於分頁 List<Employee> list = query.list();//查詢
使用具名參數: (我的hinernate 版本hibernate-core-5.4.5.Final.jar)
from domain.Employee where id = :id
query.setString("id","101");//這個版本已經不推薦使用了,代替的方案如下:
query.setParameter("id",101, IntegerType.INSTANCE);//什麼類型就用xxxType.INSTANCE
使用Criteria對象
Criteria criteria = session.createCriteria(Employee.class); criteria.add(Restrictions.eq("id",101)); List<Employee> list = criteria.list();//不夠這個版本已經不這樣使用了,在後續的版本中會被移除
替代方式: https://stackoverflow.com/questions/40720799/deprecated-createcriteria-method-in-hibernate-5
//首先獲取CriteriaBuilder CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); //獲取CriteriaQuery對象 CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class); //用於條件查詢 Root<Employee> root = criteriaQuery.from(Employee.class); //拿id=101的記錄 criteriaQuery.select(root).where(root.get("id").in(101)); //創建query對象 Query<Employee> query1 = session.createQuery(criteriaQuery); List<Employee> employees = query1.list();
使用本地sql
Query<Employee> query = session.createSQLQuery("select * from tb_employee where id = :id");
query.setParameter("id",101, IntegerType.INSTANCE);//設置具名參數
List<Employee> list = query.list();
五、hibernate的三種對象狀態
1、瞬時態,(new 出來的對象處於瞬時態)
2、遊離態,(數據庫中存在,但是session中不存在的對象)
3、持久態,(數據庫中存在,同時session中也存在的對象)
這裏我提出一個問題,就是瞬時態和遊離態的區分,感覺界限不太明顯。持久態的最好區分,就是數據庫中和都存在的實體,比如你save、find、load、list等等都是會把實體存在session中,此時就是持久態了。但是比如持久態的對象調用session的clear、evict、close等方法,都會將實體移除session,那麼此時的實體,跟數據庫是對應的,比如他們的主鍵是一樣。那麼這個對應就是遊離態的話。存在一種情況,我new一個對象(將遊離態的實體傳入賦值),那麼這個新new的對象是瞬時態的還是遊離態的呢?(這個是我一直不太理解的地方,知道的大神麻煩指點一下)(其實可不可這樣理解,就針對實體的主鍵而言,如果session的有一個實體和數據庫實體主鍵一致,那麼這個session的實體就是持久態;如果一個實體不存在session中,同時它的的主鍵在數據庫中有一條記錄跟它對應,那麼這個就是遊離態的實體;如果一個實體不存在主鍵或者主鍵在數據庫中找不和它相對的記錄,那麼這個就是瞬時態)
六、在工作記得,在一個會話中,如果如果操作多張表,比如A表和B表。A表呢,你需要返回一些數據,然後你通過find的方式找到entity,然後你在entity中某個字段的值改了,比如image="www.xxxx.jpg",你要加水印,改了image="www.xxxx.jpg-image_big"
然後你返回給前端,就可以展示有水印的圖片。一開始你發現沒啥問題的,但是突然又有一個需求,說是要對這個請求進行記錄,比如要保存這個請求的訪問時間啥的,那麼就需要往B表插入一條數據。此時你會發現A表中,數據庫image的值也被改了。
這是因爲,當持久態的實體,被修改後,執行flush、session.close等操作,會將數據更新到數據庫中(工作中被坑過幾次)。