Hibernate註解開發
Hibernate開發步驟
1.匯入Hibernate開發包中lib資料夾中required下的所有jar包
2.在src根目錄建立hibernate主配置檔案,hibernate.cfg.xml,cfg:configuration配置。
主配置檔案如下:
<?xml version="1.0" encoding="UTF-8"?> <!--匯入標籤庫:在Hibernate核心開發包中hibernate-configuration-3.0.dtd中--> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- 配置session-factory:要配置的位置在: hibernate解壓縮後的檔案/project/etc/hibernate.properties --> <session-factory> <!-- 資料庫連線引數 --> <!-- 使用property標籤對SessionFactory屬性進行配置 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 連線本地mysql可以省略地址 --> <property name="hibernate.connection.url">jdbc:mysql:///servletdb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">1234</property> <!--配置currentSession:當前執行緒對應session--> <propertyname="hibernate.current_session_context_class">thread</property> <!-- hibernate自動生成sql,將sql展示出來 --> <property name="show_sql">true</property> <!-- 對sql格式化輸出,將sql變美觀 --> <property name="hibernate.format_sql">true</property> <!-- 配置hibernate方言:hibernate.dialect 因為Hibernate無需編寫sql,但其底層需要把程式碼翻譯成sql;方言也就是告知hibernate以何種sql語句進行翻譯--> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 配置hibernate對映檔案地址,對映檔案是實體類和資料庫表中對應的表的配置。 --> <mapping resource="entity/User.hbm.xml"/> </session-factory> </hibernate-configuration>
hibernate中的session相當於Connection,一個Session表示和資料庫的一次會話。 Sessionfactory:建立session的一個工廠類,相當於DriverManager
3.編寫實體類
4.編寫實體對映檔案:描述表和實體類之間的對映關係
一個表對應一個Java類,hbm:hibernate mapping 命名:類名.hbm.xml 位置:和實體類同包
<?xml version="1.0" encoding="UTF-8"?> <!--匯入標籤庫--> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- 配置User類和t_user之間的對映關係 name:全限定名 --> <class name="entity.User" table="t_user"> <!-- 配置欄位名和屬性名之間的對映關係 先配置主鍵 name:屬性名 column:列名 --> <id name="userId" column="user_id"> <!-- generator:配置主鍵生成策略 identity:自增mysql sequence:序列oracle/DB2 uuid:32位全球唯一字串 increment:自增,不建議使用 native:由hibernate生成主鍵,不建議使用 assigned:由程式生成主鍵 --> <generator class="identity"/> </id> <!-- 使用property對普通列配置 --> <property name="userName" column="user_name"/> <property name="password" column="password"/> <property name="age" column="age"/> </class> </hibernate-mapping>
5.在hibernate主配置檔案中新增對映檔案路徑
6.編寫程式碼
Hibernate物件狀態:
三態: 初始態(Virgin):剛new出的物件 User user = new User(); 初始態物件和hibernate無關聯
持久態:呼叫hibernate save() update() load() get() Query物件的方法 等API時,物件會由初始態---->持久態 持久態的物件會被session進行管理,也就是和資料庫建立了直接關聯
遊離態(處理後的狀態):失去了session管理的物件 注意: 1.遊離態物件仍然存在,等待被GC(Garbage Collection)垃圾回收執行緒回收 2.遊離態物件有OID,主鍵值 3.遊離態物件可以重新回到持久態 saveOrUpdate(Object)
Hibernate簡單API
public class TestCRUD {
private SessionFactory sf;
@Before
public void testSessionFactory(){
//1.載入hibernate.cfg.xml
//預設載入src下根目錄下的hibernate.cfg.xml
//為一個Configuration物件
Configuration cfg = new Configuration().configure();
//2.通過Configuration建立SessionFactory
sf = cfg.buildSessionFactory();
}
@Test
public void testAdd(){
//2.通過SessionFactory獲取Session
Session session = sf.openSession();
//3.開啟事務,hibernate預設不會自動提交事務
Transaction tx = session.beginTransaction();
//4.呼叫hibernateAPI完成CRUD
User user = new User();
user.setUserName("ss");
user.setPassword("ss");
user.setAge(10);
//session.save(Object):把該Java物件入庫
session.save(user);
//5.操縱完畢後提交事務
tx.commit();
//6.關閉Session
session.close();
}
@Test
public void testDelete(){
//hibernate預設按主鍵刪除,物件主鍵屬性必須有值
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setUserId(5);
//session.delete(Object):刪除該物件對應的資料庫記錄
session.delete(user);
tx.commit();
session.close();
}
@Test
public void testQuery(){
//按主鍵查詢:get/load
//使用openSession查詢可以不開啟事務
Session session = sf.openSession();
//session.get(類物件,主鍵值)
User user = session.load(User.class, 11);
System.out.println(user);
session.close();
}
@Test
public void testUpdate(){
//先查後改
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
//查出一個User
User user = session.load(User.class, 11);
user.setUserName("GayP");
// session.update(user);
tx.commit();
session.close();
}
}
session.get/load(類物件,主鍵值)
get/load的區別:
1.get是立即載入,使用get會立刻向資料庫傳送sql語句
load是延遲載入,在呼叫物件的方法或者屬性前不傳送sql,當呼叫物件的方法或者屬性時才傳送sql
2.get不存在的主鍵,返回值為null
load會丟擲ObjectNotFoundException
複雜查詢: 1.按ID查:get/load 2.使用HQL進行查詢 Hibernate Query Language:HQL HQL是一種類SQL語句: 1.HQL沒有表的概念,表名統一替換為類名 2.HQL沒有列的概念,列名統一替換屬性名 3.無select * from 類名: from 類名 查詢所有列 一個應用一般只需要一個SessionFactory 封裝HibernateUtil工具類實現SessionFactory單例
先實現一個HibernateUtil類,並測試Query物件
public class HibernateUtil {
private static Configuration cfg;
private static SessionFactory sf;
//事務寫成共有的,外界需要用
public static Transaction tx;
static{
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
/**
* 獲取Session物件
*/
public static Session getSession(){
Session session = sf.openSession();
tx = session.beginTransaction();
return session;
}
}
public class TestQuery {
@Test
public void testAllUser(){
Session session = HibernateUtil.getSession();
//1.編寫HQL
String hql = "from User where userName =:username"
+ " and password =:password";
//2.通過session建立Query物件並傳入HQL語句
Query query = session.createQuery(hql);
//3.呼叫Query物件的API完成查詢
query.setParameter("username", "GayP");
query.setParameter("password", "ooxx1");
List<User> users = query.list();
System.out.println(users==null);
System.out.println(users.isEmpty());
for (User user : users) {
System.out.println(user);
System.out.println("-----------");
}
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testFindAllUser2(){
Session session = HibernateUtil.getSession();
//1.編寫HQL
String hql = "from User";
//2.通過HQL建立Query物件
Query query = session.createQuery(hql);
Iterator<User> it = query.iterate();
while(it.hasNext()){
User user = it.next();
System.out.println(user);
System.out.println("-----------");
}
}
@Test
public void testQueryUserByName(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName = ?";
Query query = session.createQuery(hql);
//給佔位符賦值
//注意HQL佔位符從0開頭
query.setParameter(0, "GayP");
//注意:返回值為單行記錄才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName2(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//給佔位符賦值
query.setParameter("username", "GayP");
query.setParameter("password", "ooxx");
//注意:返回值為單行記錄才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName3(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//把引數封裝為一個map:
//key:引數名
//value:引數值
Map<String, Object> parameters =
new HashMap<String,Object>();
parameters.put("username", "GayP");
parameters.put("password", "ooxx");
//給佔位符賦值
query.setProperties(parameters);
//注意:返回值為單行記錄才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName4(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//把引數封裝為一個JavaBean:
UserQueryBean qb = new UserQueryBean();
qb.setUsername("GayP");
qb.setPassword("ooxx");
//給佔位符賦值
query.setProperties(qb);
//注意:返回值為單行記錄才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
//投影查詢1:封裝為JavaBean
@Test
public void testHeadHard1(){
Session session = HibernateUtil.getSession();
String hql = "select new entity.User(userName,password)"
+ " from User";
List<User> users = session.createQuery(hql).list();
for (User user : users) {
System.out.println(user);
System.out.println("----------");
}
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testHeadHard2(){
Session session = HibernateUtil.getSession();
String hql = "select new Map(userName,password) from User";
//查詢一行結果對應一個Map
//多個Map的集合就是一個List
List<Map<String, Object>> result =
session.createQuery(hql).list();
for (Map<String, Object> map : result) {
//遍歷Map
for (Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":"
+ entry.getValue());
}
//內層迴圈走完,一行遍歷結束
System.out.println("-------------");
}
HibernateUtil.tx.commit();
session.close();
}
}
如何給hql中的佔位符賦值: 引數較少時 1.query.setParameter(“引數名”,引數值);
引數較多時 2.把引數封裝成Map query.setProperties(map); 3.把引數封裝為一個JavaBean query.setProperties(Java物件);
投影查詢
查詢部分列: 1.select new entity.User(userName,password) from User 把查詢結果封裝成JavaBean 注意:該類中必須有相應的構造 2.select new Map(屬性名1,屬性名2…) from 類名 把查詢結果封裝成Map Map的key是下標,value就是屬性值 3.hql:select 屬性名1,屬性名2… from 類名 使用Object[]封裝查詢結果: 一行記錄對應一個Object[],多行記錄對應一個List<Object[]> 注意:只能封裝查詢結果,無法查詢屬性名或下標。
openSession和getCurrentSession的區別
1.openSession無需配置getCurrentSession需要配置 在主配置檔案中新增 <propertyname=“hibernate.current_session_context_class”>thread current:當前執行緒 一個事務對應一個執行緒 當前事務 CurrentSession:執行緒繫結session 1.當前事務對應的session 2.一個事務對應一個session 事務結束:commiy rollback session物件自動銷燬(不需要再呼叫session.close();方法) 3.CurrentSession在事務結束後,無需也不能close該session 注意: CurrentSession是和事務繫結的,沒有事務也就沒有session 獲取CurrentSession必須開啟事務 openSession無需開啟事務 4.CurrentSession是執行緒安全的 openSession是執行緒非安全的,有可能產生執行緒併發問題
載入方式
一.延遲載入的概念
當Hibernate從資料庫中載入某個物件時,不載入關聯的物件,
只是生成了代理物件,獲取使用session中的load的方法(在沒有
改變lazy屬性為false的情況下)獲取到的也是代理物件,所以在上
面這幾種場景下就是延遲載入。
二.立即載入的概念
當Hibernate從資料庫中載入某個物件時,載入關聯的物件,
生成的實際物件,獲取使用session中的get的方法獲取到的是實際物件。
三.為什麼要使用延遲載入
延遲載入策略能避免載入應用程式不需要訪問的關聯物件,以提高
應用程式的效能。
四.立即載入的缺點 Hibernate在查詢某個物件時,立即查詢與之關聯的物件,我們
可以看出這種載入策略存在兩大不足
1.select的語句數目太多,需要頻繁的訪問資料庫,會影響查詢的效能。
2.在應用程式只需要訪問要的物件,而不需要訪問與他關聯的物件
的場景下,載入與之關聯的物件完全是多餘的操作,這些多餘的操
作是會佔記憶體,這就造成了記憶體空間的浪費。
Hibernate在物件-關係對映問價中配置載入策略(以檔案形式對映) I.類級別: 元素中lazy屬性的可選值為true(延遲載入)和false(立即載入); 元素中的lazy屬性的預設值為true II.一對多關聯級別: 元素中的lazy屬性的可選值為:true(延遲載入),extra(增強延遲載入)和false(立即載入); 元素中的lazy屬性的預設值為true III.多對一關聯級別: 元素中lazy屬性的可選值為:proxy(延遲載入),no-proxy(無代理延遲載入)和false(立即載入) 元素中的lazy屬性的預設值為proxy