hibernate入門
1、ORM框架:object relational mapping用於實現面向對象編程語言裏不同數據類型系統的數據之間的轉換。
Hibernate是一個數據持久化層的ORM框架.它是輕量級的JavaEE應用的持久層解決方案,是一個關係數據庫ORM框架
ORM 就是通過將Java對象映射到數據庫表,通過操作Java對象,就可以完成對數據表的操作
Hibernate提供了對關係型數據庫增刪改成操作
hibernate的優點:
- Hibernate對JDBC訪問數據庫的代碼做了封裝,大大簡化了數據訪問層繁瑣的重複性代碼
- Hibernate是一個基於jdbc的主流持久化框架,是一個優秀的orm實現,它很大程度的簡化了dao層編碼工作 session.save(User);
- Hibernate使用java的反射機制
- Hibernate的性能非常好,因爲它是一個輕量級框架。映射的靈活性很出色。它支持很多關係型數據庫,從一對一到多對多的各種複雜關係
入門案例:
1、編寫流程
- 導入jar包
- 創建數據庫和表
- 編寫核心配置文件(hibernate.cfg.xml)–> 配置獲得鏈接等參數
- 編寫映射文件 hibernate mapping(*.hbm.xml)
- 使用api測試
一、創建表
create database h_db;
use h_db;
create table t_user(
id int auto_increment primary key,
username varchar(50),
password varchar(30)
);
二、導入jar包:
- hibernate3.jar
- \lib\required
- jap規範:lib\jpa
- mysql驅動包
包的含義:
三、編寫JavaBean + 映射文件
package com.zeroyoung.domain;
public class User {
/*
* create table t_user(
id int auto_increment primary key,
username varchar(50),
password varchar(30)
);
*/
private Integer uid;
private String username;
private String password;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password="
+ password + "]";
}
}
在javabean的同一目錄下創建一個User.hbm.xml的文件
這個xml的文件的約束在hibernate3.jar/org.hibernate/hibrenate-mapping-30.dtd
<?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">
<!-- ORM元數據,表對象關係映射文件
package:配置改配置文件中類所在的包 -->
<hibernate-mapping >
<!-- class: 配置實體與表的關係
name : 填寫實體的完整類名
table: 與實體對應表的名稱
dynamic-insert:動態插入 默認值是false
true=>如果字段值爲null,不參與insert語句
dynamic-update:動態更新 默認值"false"
true=> 沒改動過的屬性,將不會生成到update語句中
-->
<class name="com.zeroyoung.domain.User" table="t_user">
<!-- 主鍵的聲明 -->
<!-- id: 配置實體與表中 id對應
name: user對象中標識主鍵的屬性名稱
column: 主鍵在表中的列名
length: 列的數據長度
unsaved-value(不常用): 指定主鍵爲什麼值時,當做null來處理.
access(強烈推薦不要用):field 那麼在操作屬性時,會直接操作對應的字段而不是get/set方法
-->
<id name="uid" column="id" length="255">
<!-- 主鍵生成策略,由數據庫控制 -->
<!-- generator:主鍵生成策略
1.increment 數據庫自己生成主鍵. 先從數據庫中查詢最大的ID值,將ID值加1作爲新的主鍵
2.identity 依賴於數據的主鍵自增功能
3.sequence 序列,依賴於數據中的序列功能(Oracle).
4.hilo(純瞭解,永遠用不到) : Hibernate自己實現序列的算法,自己生成主鍵. (hilo算法 )
5.native 自動根據數據庫判斷,三選一. identity|sequence|hilo
6.uuid 生成32位的不重複隨機字符串當做主鍵
7.assigned 自己指定主鍵值. 表的主鍵是自然主鍵時使用.
-->
<generator class="native"></generator>
</id>
<!-- property : 實體中屬性與表中列的對應
name : 實體中屬性名稱
column : 表中列的名稱
length : 數據長度
precision: 小數點後的精度
scale: 有效位數
insert(一般不用): 該屬性是否加入insert語句.
update(一般不用): 該屬性是否加入update語句.
not-null : 指定屬性的約束是否使用 非空
unique : 指定屬性的約束是否使用 唯一
-->
<property name="username" column="username"/>
<property name="password" column="password"/>
</class>
</hibernate-mapping>
四、編寫核心配置文件
在src目錄下面編寫配置文件hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<!-- property:元素用於配置hibrenate中的屬性,方式爲鍵值對 -->
<!-- hibernate.connection.driver_class:數據庫連接驅動 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!--hibernate.connection.username: 數據庫連接用戶名 -->
<property name="hibernate.connection.username">root</property>
<!-- 數據庫連接密碼 -->
<property name="hibernate.connection.password">root</property>
<!-- 數據庫連接的地址,路徑 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/h_day01_db</property>
<!-- 操作數據庫時,會向控制檯打印sql語句 -->
<property name="show_sql">true</property>
<!-- 格式化sql語句 -->
<property name="format_sql">true</property>
<!-- hbm2ddl.auto: 生成表結構的策略配置
update(最常用的取值): 如果當前數據庫中不存在表結構,那麼自動創建表結構.
如果存在表結構,並且表結構與實體一致,那麼不做修改
如果存在表結構,並且表結構與實體不一致,那麼會修改表結構.會保留原有列.
create(很少):無論是否存在表結構.每次啓動Hibernate都會重新創建表結構.(數據會丟失)
create-drop(極少): 無論是否存在表結構.每次啓動Hibernate都會重新創建表結構.每次Hibernate運行結束時,刪除表結構.
validate(很少):不會自動創建表結構.也不會自動維護表結構.Hibernate只校驗表結構. 如果表結構不一致將會拋出異常.
-->
<property name="hbm2ddl.auto">update</property>
<!-- 數據庫方言配置
org.hibernate.dialect.MySQLDialect (選擇最短的)
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- hibernate.connection.autocommit: 事務自動提交 -->
<property name="hibernate.connection.autocommit">true</property>
<!-- 將Session與線程綁定=> 只有配置了該配置,才能使用getCurrentSession -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入ORM 映射文件
填寫src之後的路徑
-->
<mapping resource="com/zeroyoung/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
五、測試:
@Test
public void tet() {
// 1.加載配置文件獲取核心配置核心對象
// 1.1 調用configure() 方法=> 加載src下名爲hibernate.cfg.xml
// 1.2 如果配置文件不符合默認加載規則.我們可以調用
// new Configuration().configure(file); 通過file加載
// new Configuration().configure(path); 通過路徑加載
// 1.3 可以通過Configuration對象加載 映射文件(不推薦)
// 推薦hibernate.cfg.xml 使用 mapping 屬性引入配置文件
// 規範: 1>orm映射文件名稱與實體的簡單類名一致
// 2>orm映射文件 需要與實體的類在同一包下
Configuration config = new Configuration().configure();
// 2.獲取sessionFactory,相當於連接池
// 根據Configuration 配置信息創建 SessionFactory
SessionFactory factory = config.buildSessionFactory();
// 3.獲取會話session,相當於serlvet重點connection
// 3.1 openSession => 獲得一個全新的Session對象
// 3.2 getCurrentSession => 獲得與當前線程綁定的session對象
// 調用getCurrentSession 需要加上一個配置: <property
// name="hibernate.current_session_context_class">thread</property>
Session session = factory.openSession();
User u = new User();
u.setPassword("1233");
u.setUsername("zhon");
// 4.操作數據庫
session.save(u);
// 5.關閉資源
session.close();
factory.close();
}
api詳解
- Configuration配置對象
我們編寫的hibernate.cfg.xml配置文件需要使用 Configuration來加載,加載的方式有幾種。常見的使用方式如下:
Configuration config = new Configuration().configure();
這裏configure()方法就是加載src下名爲hibernate.cfg.xml
同時,它也提供了有參數的構造方法來使用,當我們的配置文件的不符合默認加載規則,我們可以調用如下的方法
- new Configuration().configure(file); 通過file加載
- new Configuration().configure(path); 通過路徑加載
####SessionFactory工廠
SessionFactory 相當於java web連接池,用於管理所有session
獲得方式:SessionFactory factory = config.buildSessionFactory();
sessionFactory hibernate緩存配置信息 (數據庫配置信息、映射文件,預定義HQL語句 等)
SessionFactory線程安全,可以是成員變量,多個線程同時訪問時,不會出現線程併發訪問問題。
提供api:
打開一個新的會話:
Session session = factory.openSession();
這裏得到的session是重新創建的session會話
得到當前線程綁定的session
Session session = getCurrentSession()
這裏是使用當前線程綁定的session會話,如果當前線程沒綁定session則先創建一個session對象,然後綁定之後返回。
要想使用當前線程綁定session就需要在配置文件中加上這句話:
<property name="hibernate.current_session_context_class">thread</property>
這個方法主要是跟事務的提交有關係,事務關閉時,會自動把與當前線程關聯的session關閉,並刪除
Session 會話
Session 相當於 JDBC的 Connection – 會話,我們是通過session來操作po(persistent object ,用於與數據庫交互數據。–dao層 (JavaBean + hbm ))對象的
session是單線程的,線程不安全,不能編寫成員變量
session中的幾個api方法:
- save 保存
- update 更新
- delete 刪除
- get 通過id查詢,如果沒有 null
- load 通過id查詢,如果沒有拋異常
- createQuery(“hql”) 獲得Query對象
- createCriteria(Class) 獲得Criteria對象
保存對象上面的例子已近說明,更新對象那個的方法如下
User user = (User) session.get(User.class, 1);
user.setUsername("湯姆");
session.update(user);
刪除:
// 先查詢出你要修改的對象
User user = (User) session.get(User.class, 1);
// 刪除
session.delete(user);
get查詢:
第一個參數時候javabean,第二個是id的值
// 先查詢出你要修改的對象
User user = (User) session.get(User.class, 2);
load查詢:
// 先查詢出你要修改的對象
User user = (User) session.load(User.class, 2);
load與get的區別:
get方法被調用時立刻 發送sql語句查詢、load調用時並沒有查詢數據庫,當我們需要使用該對象的時候,才查詢數據
createQuery編寫查詢語句
查詢所有的用戶
// HQL語言 => Hibernate Query Language
// createQuery 傳入hql語句查詢,完整類名字
// 相當於select * from t_user;
Query query = session.createQuery("from com.zeroyoung.domain.User");
List<User> list = query.list();
System.out.println(list);
Criteria查詢所有(一般很少使用)
// Criteria 查詢 => Hibernate獨創的面向對象的查詢=> 無語句
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
支持原生的sql語句查詢:
// 原生的Sql查詢
SQLQuery query = session.createSQLQuery("select * from t_user");
// addEntity 將查詢結果封裝到指定對象中
query.addEntity(User.class);
List<User> list = query.list();
事務Transaction
開啓事務 beginTransaction()
獲得事務 getTransaction()
提交事務:commit()
回滾事務:rollback()
try{
//開啓
//session操作
//提交
} catch(e){
//回滾
}
query對象
通過createQuery()方法,我們會得到一個query對象,它能幫助我們完成一些列的事情。
api:
- list() 查詢所有
- uniqueResult()獲取一個結果,如果沒有查到返回null,如果查詢到多條拋出異常
- setFirstResult(int)分頁,開始索引的數startIndex
- setMaxResults(int) 分頁,每頁顯示個數 pageSize
Query query = session.createQuery("from com.zeroyoung.domain.User");
// 分頁 limit index,count;
// 指定結果從第幾個開始拿
query.setFirstResult(0);
// 指定拿幾個
query.setMaxResults(2);
// query.list() 將hql語句執行,並返回結果(多行)
List<User> list = query.list();
System.out.println(list);
//uniqueResult 將hql語句執行,並返回結果(一行),用於在createquery中添加條件
//User u = (User) query.uniqueResult();
//System.out.println(u);
Criteria對象
QBC(query by criteria),hibernate提供純面向對象查詢語言,提供直接使用PO對象進行操作。
獲得方式:Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("username", "tom"));
// Restrictions.gt(propertyName, value) 大於
// Restrictions.ge(propertyName, value) 大於等於
// Restrictions.lt(propertyName, value) 小於
// Restrictions.le(propertyName, value) 小於等於
// Restrictions.like(propertyName, value) 模糊查詢,注意:模糊查詢值需要使用 % _
創建一個工具類
public class H3Utils {
// 會話工廠,整個程序只有一份。
private static SessionFactory factory;
static{
//1 加載配置
Configuration config = new Configuration().configure();
//2 獲得工廠
factory = config.buildSessionFactory();
//3 關閉虛擬機時,釋放SessionFactory
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("虛擬機關閉!釋放資源");
sf.close();
}
}));
}
/**
* 獲得一個新的session
* @return
*/
public static Session openSession(){
return factory.openSession();
}
/**
* 獲得當前線程中綁定session
* * 注意:必須配置
* @return
*/
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
}
配置文件詳解
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<!-- property 元素用於配置Hibernate中的屬性
鍵:值
-->
<!-- hibernate.connection.driver_class : 連接數據庫的驅動 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- hibernate.connection.username : 連接數據庫的用戶名 -->
<property name="hibernate.connection.username">root</property>
<!-- hibernate.connection.password : 連接數據庫的密碼 -->
<property name="hibernate.connection.password">1234</property>
<!-- hibernate.connection.url : 連接數據庫的地址,路徑 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/EE19Day01</property>
<!-- show_sql: 操作數據庫時,會 向控制檯打印sql語句 -->
<property name="show_sql">true</property>
<!-- format_sql: 打印sql語句前,會將sql語句先格式化 -->
<property name="format_sql">true</property>
<!-- hbm2ddl.auto: 生成表結構的策略配置
update(最常用的取值): 如果當前數據庫中不存在表結構,那麼自動創建表結構.
如果存在表結構,並且表結構與實體一致,那麼不做修改
如果存在表結構,並且表結構與實體不一致,那麼會修改表結構.會保留原有列.
create(很少):無論是否存在表結構.每次啓動Hibernate都會重新創建表結構.(數據會丟失)
create-drop(極少): 無論是否存在表結構.每次啓動Hibernate都會重新創建表結構.每次Hibernate運行結束時,刪除表結構.
validate(很少):不會自動創建表結構.也不會自動維護表結構.Hibernate只校驗表結構. 如果表結構不一致將會拋出異常.
-->
<property name="hbm2ddl.auto">update</property>
<!-- 數據庫方言配置
方言:爲不同的數據庫,不同的版本,生成sql語句(DQL查詢語句)提供依據
mysql 字符串 varchar
orcale 字符串 varchar2
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- hibernate.connection.autocommit: 事務自動提交 -->
<property name="hibernate.connection.autocommit">true</property>
<!-- 將Session與線程綁定=> 只有配置了該配置,才能使用getCurrentSession -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入ORM 映射文件
填寫src之後的路徑
-->
<mapping resource="com/itheima/a_hello/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate中持久化類–javabean
1、javabean的編寫規範
- 提供一個無參數 public訪問控制符的構造器
- 提供一個標識屬性,映射數據表主鍵字段
- 所有屬性提供public訪問控制符的 set get 方法(javaBean)
- 標識屬性應儘量使用基本數據類型的包裝類型
- 不要用final修飾實體 (將無法生成代理對象進行優化)
2、持久化對象的唯一標識OID
- java按地區區分同一個類的不同對象
- 關係數據庫用主鍵區分同一條記錄
- Hibernate使用OID來建立內存中的對象和數據庫中記錄的對應關係
結論:對象的OID和數據庫的表的主鍵對應。爲保證OID的唯一性,應該讓Hibernate來爲OID付值
區分自然主鍵和代理主鍵
一、主鍵需要具備:
- 不爲空
- 不能重複
不能改變
自然主鍵:在業務中,某個屬性符合主鍵的三個要求.那麼該屬性可以作爲主鍵列.
代理主鍵:在業務中,不存符合以上3個條件的屬性,那麼就增加一個沒有意義的列.作爲主鍵.
基本數據與包裝類型
- 基本數據類型和包裝類型對應hibernate的映射類型相同
- 基本類型無法表達null、數字類型的默認值爲0。
- 包裝類默認值是null。當對於默認值有業務意義的時候需要使用包裝類。
數據類型的對應圖標表
普通屬性
<hibernate-mapping>
package 用於配置PO類所在包
例如: package="com.itheima.d_hbm"
<class> 配置 PO類 和 表 之間對應關係
name:PO類全限定類名
例如:name="com.itheima.d_hbm.Person"
如果配置 package,name的取值可以是簡單類名 name="Person"
table : 數據庫對應的表名
dynamic-insert="false" 是否支持動態生成insert語句
dynamic-update="false" 是否支持動態生成update語句
如果設置true,hibernate底層將判斷提供數據是否爲null,如果爲null,insert或update語句將沒有此項。
普通字段
<property>
name : PO類的屬性
column : 表中的列名,默認name的值相同
type:表中列的類型。默認hibernate自己通過getter獲得類型,一般情況不用設置
取值1: hibernate類型
string 字符串
integer 整形
取值2: java類型 (全限定類名)
java.lang.String 字符串
取值3:數據庫類型
varchar(長度) 字符串
int 整形
<property name="birthday">
<column name="birthday" sql-type="datetime"></column>
</property>
javabean 一般使用類型 java.util.Date
jdbc規範提供3中
java類型 mysql類型
java.sql.Date date
java.sql.time time
java.sql.timestamp timestamp
null datetime
以上三個類型都是java.util.Date子類
length : 列的長度。默認值:255
not-null : 是否爲null
unique : 是否唯一
access:設置映射使用PO類屬性或字段
property : 使用PO類屬性,必須提供setter、getter方法
field : 使用PO類字段,一般很少使用。
insert 生成insert語句時,是否使用當前字段。
update 生成update語句時,是否使用當前字段。
默認情況:hibernate生成insert或update語句,使用配置文件所有項
注意:配置文件如果使用關鍵字,列名必須使用重音符
主鍵
<id>配置主鍵
name:屬性名稱
access="" 設置使用屬性還是字段
column="" 表的列名
length="" 長度
type="" 類型
<generator> class屬性用於設置主鍵生成策略
1.increment 由hibernate自己維護自動增長
底層通過先查詢max值,再+1策略
不建議使用,存在線程併發問題
2.identity hibernate底層採用數據庫本身自動增長列
例如:mysql auto_increment
3.sequence hibernate底層採用數據庫序列
例如:oracle 提供序列
4.hilo
</generator>
5.native 根據底層數據庫的能力選擇 identity、sequence 或者 hilo 中的一個。【】
##以上策略使用整形,long, short 或者 int 類型
6.uuid 採用字符串唯一值【】
##以上策略 代理主鍵,有hibernate維護。
7.assigned 自然主鍵,由程序自己維護。【】