一、hibernate 基礎
1、ORM 框架
- 對象關係映射(Object Relational Mapping,簡稱ORM)是通過使用描述對象和數據庫之間映射的元數據,將面嚮對象語言程序中的對象自動持久化到關係數據庫中。
- ORM(Object Relational Mapping)框架採用元數據來描述對象與關係映射的細節,元數據一般採用XML格式,並且存放在專門的對象一映射文件中。
2、hibernate
- Hibernate是一個開放源代碼的對象關係映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與數據庫表建立映射關係,是一個全自動的orm框架。
- hibernate可以自動生成SQL語句,自動執行,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。
- Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的JaveEE架構中取代CMP,完成數據持久化的重任。
- Hibernate是輕量級JavaEE應用的持久層解決方案,是一個關係數據庫ORM框架
- ORM 就是通過將Java對象映射到數據庫表,通過操作Java對象,就可以完成對數據表的操作
- Hibernate提供了對關係型數據庫增刪改成操作
3、hibernate 的優點
- Hibernate對JDBC訪問數據庫的代碼做了封裝,大大簡化了數據訪問層繁瑣的重複性代碼
- Hibernate是一個基於jdbc的主流持久化框架,是一個優秀的orm實現,它很大程度的簡化了dao層編碼工作 session.save(User);
- Hibernate使用java的反射機制
- Hibernate的性能非常好,因爲它是一個輕量級框架。映射的靈活性很出色。它支持很多關係型數據庫,從一對一到多對多的各種複雜關係
二、案例
工具:Meven、 IntelliJ IDEA、MySQL
第一步:
引入jar 包:mysql-connector-java
、hibernate-core
、junit
第二步:編寫JavaBean對象、映射文件
JavaBean 對象——User.java
package cn.lemon.domain;
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
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;
}
}
映射文件——User.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--class 表示類和表的映射,name:映射的實體類;table:數據庫表-->
<class name="cn.lemon.domain.User" table="user">
<!--映射主鍵字段,name = id 表示:主鍵字段-->
<id name="id">
<!--數據庫裏的id-->
<column name="id_"/>
<!-- 主鍵生成策略:
* identity 表示自增的主鍵-->
<generator class="identity"/>
</id>
<!--映射其他的字段;property 裏的 name 表示實體類裏的字段; column 裏的 name 表示數據庫表的字段-->
<property name="username">
<column name="username_"/>
</property>
<property name="password">
<column name="password_"/>
</property>
</class>
</hibernate-mapping>
第三步:編寫核心配置文件(hibernate.cfg.xml)用來配置獲得鏈接等參數
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- SessionFactory,相當於連接池配置 -->
<session-factory>
<property name="connection.url">jdbc:mysql:///db_hibernate</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">lemon</property>
<property name="hbm2ddl.auto">update</property>
<!-- 方言:指定當前hibernate使用的數據庫 -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 添加映射文件 -->
<mapping resource="cn/lemon/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第四步:測試
package cn.lemon.test;
import cn.lemon.domain.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class HibernateTest {
@Test
public void test01() {
User user = new User();
user.setUsername("詹姆斯");
user.setPassword("123321");
Configuration cfg = new Configuration().configure("cn/lemon/domain/hibernate.cfg.xml");//加載配置文件獲得核心配置對象,默認讀取 classpath/hibernate.cfg.xml
SessionFactory sf = cfg.buildSessionFactory(); //獲得工廠 SessionFactory,相當於連接池
Session session = sf.openSession();//獲得會話session,相當於鏈接Connection
Transaction tx = session.beginTransaction(); //啓動事務,hibernate和mybatis都是自動提交事務關閉
session.save(user); //持久化操作
tx.commit();//提交事務
session.close();//釋放資源,關閉 Session
sf.close();//釋放資源,關閉工廠類
}
}
三、API 詳解
1、體系結構
2、Configuration 配置對象
- hibernate 核心配置文件種類
- hibernate.cfg.xml 通常使用xml配置文件,可以配置內容更豐富。
- hibernate.properties 用於配置key/value 形式的內容,key不能重複的。配置有很多的侷限性。一般不用。
1、提供構造 new Configuration() hibernate將自動加載 hibernate.properties文件
hibernate.properties文件必須存放在類路徑(src)下
2、提供方法 configure() 將加載src下的hibernate.cfg.xml
3、擴展api
- configure(String) 加載指定目錄下的 xml文件
4、手動加載配置文件
- config.addResource(“com/lxs/a_hello/User.hbm.xml”);// 手動加載指定的配置文件
- config.addClass(User.class);// 手動加載指定類,對應的映射文件 User–> User.hbm.xml
3、SessionFactory 工廠
- SessionFactory 相當於java web連接池,用於管理所有session
- 獲得方式:config.buildSessionFactory();
- sessionFactory hibernate緩存配置信息 (數據庫配置信息、映射文件,預定義HQL語句 等)
- SessionFactory線程安全,可以是成員變量,多個線程同時訪問時,不會出現線程併發訪問問題。
- 提供api:
factory.openSession();
//打開一個新的會話 session,openSession需要調用close方法關閉session;factory.getCurrentSession();
//獲得當前線程中綁定的會話session;hibernate支持,將創建的session綁定到本地線程中,底層使用ThreadLocal,在程序之間共享session
1、必須在hibernate.cfg.xml 配置<property name="hibernate.current_session_context_class">thread</property>
2、如果提交或回滾事務,底層將自動關閉session
示例代碼:
package cn.lemon.b_api;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class SessionFactoryTest {
@Test
public void test(){
User user = new User();
user.setUsername("詹姆斯");
user.setPassword("123321");
Configuration cfg = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");//加載配置文件獲得核心配置對象,默認讀取 classpath/hibernate.cfg.xml
SessionFactory sf = cfg.buildSessionFactory(); //獲得工廠 SessionFactory,相當於連接池
//Session session = sf.openSession();//獲得會話session,相當於鏈接Connection
/**獲得當前線程中綁定的會話session;hibernate支持,將創建的session綁定到本地線程中,底層使用ThreadLocal,在程序之間共享session
1、必須在hibernate.cfg.xml 配置`<property name="hibernate.current_session_context_class">thread</property>`
2、如果提交或回滾事務,底層將自動關閉session*/
Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction(); //啓動事務,hibernate和mybatis都是自動提交事務關閉
session.save(user); //持久化操作
tx.commit();//提交事務
//session.close();//釋放資源,關閉 Session
sf.close();//釋放資源,關閉工廠類
}
}
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!--核心配置文件-->
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">lemon</property>
<!--方言dialect:指定hibernate 使用的數據庫-->
<property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>
<!--與本地線程綁定-->
<property name="hibernate.current_session_context_class">thread</property>
<!--映射文件-->
<mapping resource="cn/lemon/b_api/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
4、Session 會話
- Session 相當於 JDBC的 Connection
- 通過session操作PO對象 --增刪改查
- session單線程,線程不安全,不能編寫成成員變量。
- session api
save
保存update
更新delete
刪除get
通過id查詢,如果沒有 nullload
通過id查詢,如果沒有拋異常createQuery("hql")
獲得Query對象createCriteria(Class)
獲得Criteria對象
5、Transaction 事務
- 開啓事務
beginTransaction()
- 獲得事務
getTransaction()
- 提交事務
commit()
- 回滾事務
rollback()
try{
//開啓
//session操作
//提交
} catch(e){
//回滾
}
擴展:不需要手動的管理事務,之後所有的事務管理都交予spring。
示例代碼:
package cn.lemon.b_api;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import java.util.List;
public class UserDao {
/**
* 添加
*
* @param user
* @return
*/
public Integer addTest(User user) {//hibernate 返回的是添加的主鍵,而 mybatis 返回的是影響的行數
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
Integer result = null;
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
result = (Integer) session.save(user);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
sessionFactory.close();
}
return result;
}
/**
* 修改
* @param user
*/
public void updateTest(User user) {//修改是沒有返回值的
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
session.update(user);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
sessionFactory.close();
}
}
/**
* 刪除
*
* @param user user的主鍵不能爲空
*/
public void deleteTest(User user) {//修改是沒有返回值的
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
session.delete(user);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
sessionFactory.close();
}
}
/**
* 根據 id 查詢
* @param id
* @return
*/
public User findByIdTest(Integer id) {
User user = null;
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
user = (User) session.get(User.class, id);//get 方法與 load 方法的區別就是 get 不使用緩存,而load 使用緩存
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
sessionFactory.close();
}
return user;
}
/**
* 根據 id 查詢,load 使用緩存
* @param id
* @return
*/
public User findByIdTest2(Integer id) {
User user = null;
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
user = (User) session.load(User.class, id);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
//sessionFactory.close();
}
return user;
}
/**
* 查詢所有
* @return
*/
public List<User> findAll() {
List<User> userList = null;
Configuration configuration = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;//查詢所有,有事務也行,沒有也行
try {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
Query query = session.createQuery("from User");
userList = query.list();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();//如果有異常,回滾事務
} finally {
sessionFactory.close();
}
return userList;
}
}
package cn.lemon.b_api;
import org.junit.Test;
import java.util.List;
public class UserTest {
UserDao userDao = new UserDao();
@Test
public void testAdd() {//測試添加
User user = new User();
user.setUsername("馬雲");
user.setPassword("123");
userDao.addTest(user);
}
@Test
public void deleteTest() {//測試刪除
User user = new User();
user.setId(15);
userDao.deleteTest(user);
}
@Test
public void updateTest() {//測試修改
User user = new User();
user.setId(14);
user.setUsername("馬化騰");
user.setPassword("123");
userDao.updateTest(user);
}
@Test
public void findByIdTest() {//測試 get 查找
User user = userDao.findByIdTest(14);
System.out.println(user.getId() + "\t" + user.getUsername() + "\t" + user.getPassword());
User user2 = userDao.findByIdTest(123);//get 方法加載不存在的id時,get 返回 null,而load 會報錯
System.out.println(user2);//返回 null
}
@Test
public void finfById2Test() {//測試 load 查找
User user = userDao.findByIdTest2(14);//這是load 方法加載,使用類延遲加載(懶加載),不能關閉Session,如果關閉了會報錯
System.out.println(user);
}
@Test
public void findAll() {//測試查查詢所有
List<User> list = userDao.findAll();
for (User user : list) {
System.out.println(user.getId() + "\t" + user.getUsername() + "\t" + user.getPassword());
}
}
}
在上面的代碼中,有太多重複的代碼,所以需要簡化一下 UserDao,需要一個工具類 HibernateUtils
package cn.lemon.b_api.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static Configuration configuration;
private static SessionFactory sessionFactory;//會話工廠,整個程序只有一個
static {
configuration = new Configuration().configure("cn/lemon/b_api/hibernate.cfg.xml");//第一步:加載配置文件
sessionFactory = configuration.buildSessionFactory();//第二步:獲得工廠,相當於連接池
//第三步:addShutdownHook:捕獲虛擬機關閉,當關閉虛擬機時,釋放 SessionFactory 工廠
//匿名內部類的寫法:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("虛擬機關閉,釋放資源..........");
sessionFactory.close();//關閉 SessionFactory 工廠
}
}));
// lanmda 表達式的寫法
/**
Runtime.getRuntime().addShutdownHook(new Thread(() ->{
System.out.println("虛擬機關閉,釋放資源..........");
sessionFactory.close();//關閉 SessionFactory 工廠
}));*/
}
public static Session openSession() {//獲得一個新的 Session
return sessionFactory.openSession();
}
public static Session getCurrentSession() {//獲得當前線程中綁定的 Session (注意:必須配置)
return sessionFactory.getCurrentSession();
}
}
四、核心配置文件詳解
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!--Hibernate 的核心配置文件-->
<hibernate-configuration>
<!--session-factory:相當於連接池的配置-->
<session-factory>
<!--基本 4 項:用於連接數據庫,配置連接參數-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">lemon</property>
<!--與本地線程綁定,使用 getCurrentSession()-->
<property name="hibernate.current_session_context_class">thread</property>
<!--方言dialect:指定 hibernate 使用的數據庫,爲不同的數據庫不同的版本生成 SQL 語句提供依據-->
<property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>
<!--可以顯示控制檯操作數據庫的語句-->
<property name="hibernate.show_sql">true</property>
<!--格式化語句-->
<property name="format_sql">true</property>
<!--給語句註釋-->
<property name="use_sql_comments">true</property>
<!--
自動創建表
* sessionFactory:產生時,自動根據映射產生表
* 取值:
* * update:
1、如果表不存在,將創建表。
2、如果表已經存在,通過hbm映射文件更新表(添加)。(映射文件必須是數據庫對應)
3、表中的列可以多,不負責刪除。
* create :
如果表存在,先刪除,再創建。程序結束時,之前創建的表不刪除。
* create-drop:與create幾乎一樣。如果factory.close()執行,將在JVM關閉同時,將創建的表刪除了。(測試)
* validate:校驗 hbm映射文件 和 表的列是否對應,如果對應正常執行,如果不對應拋出異常。(測試)
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--配置映射文件-->
<mapping resource="cn/lemon/c_config/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
五、Hibernate 中持久化類(如:User 類)和映射文件
1、編寫規則
- 提供一個無參數 public訪問控制符的構造器
- 提供一個標識屬性,映射數據表主鍵字段
- 所有屬性提供public訪問控制符的 set get 方法(javaBean)
- 標識屬性應儘量使用基本數據類型的包裝類型
- 不要用final修飾實體 (將無法生成代理對象進行優化)
2、基本數據類型與包裝數據類型
- 基本數據類型和包裝類型對應hibernate的映射類型相同
- 基本類型無法表達null、數字類型的默認值爲0。
- 包裝類默認值是null。當對於默認值有業務意義的時候需要使用包裝類。
3、類型對應
4、Hibernate 映射文件(如:User.hbm.xml)
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--User 的 hibernate 映射文件-->
<!--
package:用於配置 PO 類所在的包
-->
<hibernate-mapping package="cn.lemon.test.domain">
<!--
class:配置 PO類 和 表 之間對應關係
name:PO類全限定類名:如果配置 package,name的取值可以是簡單類名 name="User"
table : 數據庫對應的表名
dynamic-insert="false" 是否支持動態生成insert語句
dynamic-update="false" 是否支持動態生成update語句
如果設置true,hibernate底層將判斷提供數據是否爲null,如果爲null,insert或update語句將沒有此項。
-->
<class name="cn.lemon.test.domain.User" table="user" dynamic-insert="false" dynamic-update="false">
<!--
<id>配置主鍵
name:屬性名稱
access="" 設置使用屬性還是字段
column="" 表的列名
length="" 長度
type="" 類型
<generator> class屬性用於設置主鍵生成策略
1.increment 由hibernate自己維護自動增長。底層通過先查詢max值,再+1策略;不建議使用,存在線程併發問題
2.identity hibernate底層採用數據庫本身自動增長列。例如:mysql auto_increment;建議使用
3.sequence hibernate底層採用數據庫序列。例如:oracle 提供序列
4.native 根據底層數據庫的能力選擇(自動識別數據庫) identity(Mysql)、sequence(Oracle)
以上策略使用整形,long, short 或者 int 類型
5.uuid 採用Java的UUID類產生字符串唯一值
6.guid 採用數據庫函數生成32位隨機字符串
以上策略 代理主鍵,有hibernate維護。
7.assigned 自然主鍵,由程序自己維護。
-->
<id name="id">
<column name="id_"/>
<generator class="identity"/><!--主鍵策略-->
</id>
<!--
name : PO類的屬性
column : 表中的列名,默認name的值相同
type:表中列的類型。默認hibernate自己通過getter獲得類型,一般情況不用設置
length : 列的長度。默認值:255
not-null : 是否爲null
unique : 是否唯一
access:設置映射使用PO類屬性或字段
property : 使用PO類屬性,必須提供setter、getter方法
field : 使用PO類字段,一般很少使用。
insert 生成insert語句時,是否使用當前字段。
update 生成update語句時,是否使用當前字段。
默認情況:hibernate生成insert或update語句,使用配置文件所有項
注意:配置文件如果使用關鍵字,列名必須使用重音符
-->
<property name="username">
<column name="username_"/>
</property>
<property name="password">
<column name="password_"/>
</property>
<property name="birthday">
<column name="birthday_" sql-type="datetime"></column>
</property>
</class>
</hibernate-mapping>
六、創建 BaseDao,重用 Dao 的 CRUD 操作
工具類
package cn.lemon.d_refactor.dao;
import cn.lemon.d_refactor.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import java.io.Serializable;
import java.util.List;
public class BaseDao {
public <T> Serializable add(T object) {//添加
Serializable result = null;
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
result = session.save(object);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
session.close();
}
return result;
}
public <T> void update(T object) {//修改
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
session.update(object);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
session.close();
}
}
public <T> void delete(T object) {//刪除
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
session.delete(object);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
session.close();
}
}
public <T> T get(Class<T> c, Serializable id) {//get查詢單個
T object = null;
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
object = (T) session.get(c, id);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
session.close();
}
return object;
}
public <T> T load(Class<T> c, Serializable id) {//load查詢單個
T object = null;
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtils.openSession();
transaction = session.beginTransaction();
object = (T) session.load(c, id);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
session.close();
}
return object;
}
public List list(String hql) {//查詢所有
List list = null;
Session session = null;
try {
session = HibernateUtils.openSession();
Query query = session.createQuery(hql);
list = query.list();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
return list;
}
}
package cn.lemon.d_refactor.dao;
import cn.lemon.d_refactor.domain.Student;
import java.util.List;
public class StudentDao extends BaseDao {
/**
* 增加
* @param student
*/
public void add(Student student) {
super.add(student);
}
/**
* 修改
* @param student
*/
public void update(Student student) {
super.update(student);
}
/**
* 刪除
* @param student
*/
public void delete(Student student) {
super.delete(student);
}
/**
* get加載
* @param id
* @return
*/
public Student get(String id) {
return super.get(Student.class, id);
}
/**
* load加載
* @param id
* @return
*/
public Student load(String id) {
return super.load(Student.class, id);
}
/**
* query查詢
* @return
*/
public List<Student> queryList() {
return (List<Student>) super.list("from Student");
}
}
測試類
package cn.lemon.d_refactor.test;
import cn.lemon.d_refactor.dao.StudentDao;
import cn.lemon.d_refactor.domain.Student;
import org.junit.Test;
import java.util.Date;
public class StudentTest {
StudentDao studentDao = new StudentDao();
@Test
public void testAdd() {
Student student = new Student();
student.setName("張三丰");
student.setRegisterDate(new Date());
studentDao.add(student);
}
@Test
public void testGet() {
Student student = studentDao.get("abc123");
System.out.println(student.getName());
}
}
七、Hibernate 對象狀態
1、瞬時態(臨時態)
- 獲得:一般都只直接創建(new)
- 瞬時態 轉換 持久態 一般操作:save方法、saveOrUpdate
- 瞬時態 轉換 脫管態 一般操作:通過setId方法設置數據
例如:User user = new User();
//瞬時態user.setUid(1);
//脫管態
2、持久態
-
獲得:查詢操作:get、loat、createQuery、createCriteria 等 獲得都是持久態
- 執行save之後持久態
- 執行update之後持久態
-
持久態 轉換 瞬時態 官方規定執行delete() --民間:刪除態
-
持久態 轉換 脫管態
- session沒有記錄
- session.close () 關閉
- session.clear() 清除所有
- session.evict(obj) 清除指定的PO對象
3、託管態(遊離態)
- 獲得:
創建、並設置OID的
通過api獲得 - 脫管態 轉換 瞬時態
手動去除OID,設置成默認值 - 脫管態 轉換 持久態
一般操作:update()、saveOrUpdate
@Test
public void demo01(){
User user = new User(); //瞬時態
user.setUsername("jack");
user.setPassword("1234"); //瞬時態(與oid沒有關係)
Session session = factory.openSession();
session.beginTransaction();
session.save(user); //持久態
//---- 持久態就應該有持久態的行爲(特性)
// user.setUsername("rose"); //持久態對象 被修改後,hibernate將自動生成update語句
// session.flush();
session.getTransaction().commit();
session.close();
System.out.println(user); //脫管態
}
八、關聯關係映射——一對多映射
模擬客戶與訂單:一個客戶 -> 多個訂單(Customer -> Order)
第一步:新建 Customer.java 、Order.java 實體類
package cn.lemon.e_onetomany.domain;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Integer id;
private String name;
private Set<Order> orders = new HashSet<>();/*客戶的多個訂單的 Set 集合*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
package cn.lemon.e_onetomany.domain;
public class Order {
private Integer id;
private String name;
private Customer customer;/*關聯屬性:訂單所屬的客戶*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
第二步:新建 Customer.hbm.xml 、Order.hbm.xml 映射文件
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Customer 的 hibernate 映射文件(一對多中 ”一“ 的一方)-->
<hibernate-mapping>
<class name="cn.lemon.e_onetomany.domain.Customer" table="customer_">
<id name="id" type="java.lang.Integer">
<column name="id_"/>
<generator class="native"/>
</id>
<property name="name" type="string">
<column name="name_"/>
</property>
<!--
映射一對多,由於實體類裏是 Set,這裏要用 set 映射
name:關聯屬性名
key裏的 Column :指定外鍵字段
one-to-many : 映射的關聯類
-->
<set name="orders">
<key column="cust_id_"/>
<one-to-many class="cn.lemon.e_onetomany.domain.Order"/>
</set>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Order 的 hibernate 映射文件(一對多中 ”多“ 的一方)-->
<hibernate-mapping>
<class name="cn.lemon.e_onetomany.domain.Order" table="order_">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="name">
<column name="name"/>
</property>
<!--多對一
name:關聯屬性名
column:外鍵字段,要與 Customer 中的外鍵字段一致
class : 關聯的類
-->
<many-to-one name="customer" column="cust_id_" class="cn.lemon.e_onetomany.domain.Customer"/>
</class>
</hibernate-mapping>
第三步:測試
package cn.lemon.e_onetomany.test;
import cn.lemon.d_refactor.utils.HibernateUtils;
import cn.lemon.e_onetomany.domain.Customer;
import cn.lemon.e_onetomany.domain.Order;
import org.hibernate.Session;
import org.junit.Test;
public class OnetomanyTest {
@Test
public void testCreateTable() {
HibernateUtils.getCurrentSession();//當sessionFactory產生時產生表結構
}
/**
* 客戶加載,自動加載客戶的訂單
*/
@Test
public void testGet() {
Session session = HibernateUtils.openSession();
Customer customer = (Customer) session.get(Customer.class, 2);
System.out.println(customer.getName());
System.out.println("--------------------------------------");
// System.out.println(customer.getOrders().size());
for (Order o : customer.getOrders()) {
System.out.println(o.getName());
}
session.close();
}
@Test
public void testList() {
Session session = HibernateUtils.openSession();
session.createQuery("from customer_").list();
}
/**
* 保存訂單
*/
@Test
public void demo02(){
//創建訂單,保存訂單--成功,外鍵爲null
Session session = HibernateUtils.openSession();
session.beginTransaction();
Order order = new Order();
order.setName("檯球");
//訂單所屬的客戶沒有賦值,外鍵=null
//第一種賦值
// Customer c = new Customer();
// c.setId(4);
//第二種
Customer c = (Customer) session.get(Customer.class, 3);
//設置關聯屬性,讓訂單屬於c(id=4)這個客戶
order.setCustomer(c);
session.save(order);
session.getTransaction().commit();
session.close();
}
/**
* 保存客戶和訂單:讓客戶(一)維護關聯關係
* inverse=false:因爲維護關聯關係, 添加客戶時,執行update語句關聯外鍵=客戶的主鍵
* inverse=true::因爲不維護關聯關係,添加客戶時,外鍵=null
* cascade=save-update:級聯添加和修改,客戶添加,自動客戶管理的訂單
*/
@Test
public void demo03(){
//創建客戶和訂單,客戶關聯訂單,保存客戶?
Session session = HibernateUtils.openSession();
session.beginTransaction();
//客戶和訂單
Customer customer = new Customer();
customer.setName("字母歌");
Order order1 = new Order();
order1.setName("檯球杆");
Order order2 = new Order();
order2.setName("檯球桌");
// // 客戶關聯訂單
customer.getOrders().add(order1);
customer.getOrders().add(order2);
// // 訂單關聯客戶(inverse無效)
// order1.setCustomer(customer);
// order2.setCustomer(customer);
//保存訂單,因爲設置cascade級聯添加,在添加客戶時自動添加關聯的訂單
// session.save(order1);
// session.save(order2);
//3 保存客戶
session.save(customer);
session.getTransaction().commit();
session.close();
}
/**
* 刪除客戶
* inverse=true:刪除時有外鍵數據報錯
* inverse=false:刪除時有外鍵,外鍵設置爲null
* cascade:delete:當刪除客戶時,訂單同時刪除。。。
*/
@Test
public void testDeleteCustomer(){
//創建客戶,並保存客戶--成功
Session session = HibernateUtils.openSession();
session.beginTransaction();
//必須讓客戶的訂單集合有訂單,才能級聯
Customer c = (Customer) session.get(Customer.class, 8);
session.delete(c);
session.getTransaction().commit();
session.close();
}
}
九、inverse 、cascade
1、inverse 屬性
概述: 設置關聯關係的方向,當前類是否維護關聯關係,是否維護外鍵的值,只配置在set一方(一的一方配置)
保存客戶和訂單:讓客戶(一)維護關聯關係
- inverse=false:因爲維護關聯關係, 添加客戶時,執行update語句關聯外鍵=客戶的主鍵
- inverse=true::因爲不維護關聯關係,添加客戶時,外鍵=null
2、cascade級聯操作
概述: 一方操作,級聯另外一方做相同的操作
cascade=save-update
:級聯添加和修改,客戶添加,自動客戶管理的訂單
十、關聯關係映射——多對多映射
模擬學生與課程(Student -> Course):(多 :多)
一個學生 -> 多門課程
一門課程 -> 多個學生
第一步:新建 Student.java 、Course.java 實體類
package cn.lemon.f_manytomany.domain;
import java.util.HashSet;
import java.util.Set;
public class Student {
private Integer id;
private String name;
private Set<Course> courses = new HashSet<>();
public Student() {
}
public Student(String name) {//構造函數傳值
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
package cn.lemon.f_manytomany.domain;
import java.util.HashSet;
import java.util.Set;
public class Course {
private Integer id;
private String name;
private Set<Student> students = new HashSet<>();
public Course() {
}
public Course(String name) {//構造函數傳值
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
第二步:新建 Student.hbm.xml 、Course.hbm.xml 映射文件
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Student 的 Hibernate 映射文件-->
<hibernate-mapping>
<class name="cn.lemon.f_manytomany.domain.Student" table="student">
<id name="id" type="java.lang.Integer">
<column name="id_"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="name_"/>
</property>
<!--
映射多對多
* name:關聯屬性名
* table:中間表名
* inverse:
false:當前類維護關聯關係(中間表的外鍵)
true:當前類不維護關聯關係(中間表的外鍵)
* key -> column:當前表在中間表的外鍵
* many-to-many:映射多對多
* class:另一方類路徑
* column:對方表在中間表的外鍵
-->
<set name="courses" table="student_course_" inverse="false">
<key>
<column name="student_id_" />
</key>
<many-to-many column="course_id_" class="cn.lemon.f_manytomany.domain.Course"/>
</set>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--Course 的 Hibernate 映射文件-->
<hibernate-mapping>
<class name="cn.lemon.f_manytomany.domain.Course" table="course">
<id name="id" type="java.lang.Integer">
<column name="id_"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="name_"/>
</property>
<!--
映射多對多
* name:關聯屬性名
* table:中間表名
* inverse:
false:當前類維護關聯關係(中間表的外鍵)
true:當前類不維護關聯關係(中間表的外鍵)
* key -> column:當前表在中間表的外鍵
* many-to-many:映射多對多
* class:另一方類路徑
* column:對方表在中間表的外鍵
-->
<set name="students" table="student_course_" inverse="true">
<key>
<column name="course_id_" />
</key>
<many-to-many column="student_id_" class="cn.lemon.f_manytomany.domain.Student"/>
</set>
</class>
</hibernate-mapping>
第三步:測試
package cn.lemon.f_manytomany.test;
import cn.lemon.f_manytomany.domain.Course;
import cn.lemon.f_manytomany.domain.Student;
import cn.lemon.utils.HibernateUtils;
import org.hibernate.Session;
import org.junit.Test;
public class ManytomanyTest {
@Test
public void testCreateTable() {
HibernateUtils.getCurrentSession();
}
/**
* 加載
*/
@Test
public void test2() {
Session session = HibernateUtils.openSession();
Student zhangsan = (Student) session.get(Student.class,1);
System.out.println(zhangsan.getName());
System.out.println("-------------------------");
for (Course c : zhangsan.getCourses()) {
System.out.println(c.getName());
}
System.out.println("*************************");
Course php = (Course) session.get(Course.class, 2);
System.out.println(php.getName());
System.out.println("-------------------------");
for (Student s : php.getStudents()) {
System.out.println(s.getName());
}
System.out.println("*************************");
session.close();
}
/**
* 添加
*/
@Test
public void test3() {
Session session = HibernateUtils.getCurrentSession();
session.beginTransaction();
Student zhangsan = new Student("張三");
Student lisi = new Student("李四");
Student wangwu = new Student("王五");
Student zhaoer = new Student("趙二");
Course java = new Course("java");
Course c = new Course("c#");
Course php = new Course("php");
Course hadoop = new Course("hadoop");
//因爲學員的inverse=false,所以學員可以維護關聯關係(中間的外鍵)
zhangsan.getCourses().add(java);
zhangsan.getCourses().add(c);
zhangsan.getCourses().add(hadoop);
lisi.getCourses().add(c);
lisi.getCourses().add(php);
wangwu.getCourses().add(php);
wangwu.getCourses().add(hadoop);
zhaoer.getCourses().add(java);
zhaoer.getCourses().add(php);
//cascade=save-update
session.save(java);
session.save(c);
session.save(php);
session.save(hadoop);
session.save(zhangsan);
session.save(lisi);
session.save(wangwu);
session.save(zhaoer);
session.getTransaction().commit();
}
}
十一、關聯關係映射——一對一映射(唯一索引外鍵)
第一步:新建 Person.java 、SheBao.java 實體類
package cn.lemon.g_onetoone_1.domain;
public class Person {
private Integer id;
private String name;
private SheBao sheBao;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SheBao getSheBao() {
return sheBao;
}
public void setSheBao(SheBao sheBao) {
this.sheBao = sheBao;
}
}
package cn.lemon.g_onetoone_1.domain;
public class SheBao {
private Integer id;
private String name;
private Person person;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
第二步:新建 Person.hbm.xml 、SheBao.hbm.xml 映射文件
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.lemon.g_onetoone_1.domain.Person" table="person">
<id name="id" type="java.lang.Integer">
<column name="id_"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="name_"/>
</property>
<!-- 主鍵表
property-ref:指定對方關聯屬性名,引用外鍵
-->
<one-to-one name="sheBao" class="cn.lemon.g_onetoone_1.domain.SheBao" property-ref="person"></one-to-one>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.lemon.g_onetoone_1.domain.SheBao" table="shebao">
<id name="id" type="java.lang.Integer">
<column name="id_"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="name_"/>
</property>
<!-- 外檢表
unique:唯一索引
column:外鍵
-->
<many-to-one name="person" column="person_id_" unique="true"></many-to-one>
</class>
</hibernate-mapping>
第三步:測試
package cn.lemon.g_onetoone_1.test;
import cn.lemon.d_refactor.dao.BaseDao;
import cn.lemon.g_onetoone_1.domain.Person;
import cn.lemon.g_onetoone_1.domain.SheBao;
import cn.lemon.utils.HibernateUtils;
import org.junit.Test;
public class OnetooneTest {
@Test
public void testCreateDb() {
HibernateUtils.getCurrentSession();
}
/**
* 添加
*/
@Test
public void test2() {
Person u1 = new Person();
u1.setName("張三");
Person u2 = new Person();
u2.setName("李四");
SheBao s1 = new SheBao();
s1.setName("社保1");
SheBao s2 = new SheBao();
s2.setName("社保2");
s1.setPerson(u1);
s2.setPerson(u1); //因爲張三有2個社保違反唯一約束,所以報錯。。。
BaseDao dao = new BaseDao();
dao.add(u1);
dao.add(u2);
dao.add(s1);
dao.add(s2);
}
}
十二、關聯關係映射——一對一映射(使用主鍵做外鍵)
第一步:新建 Driver.java 、JiaZhao.java 實體類
package cn.lemon.g_onetoone_2.domain;
public class Driver {
private Integer id;
private String name;
private JiaZhao jiaZhao;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JiaZhao getJiaZhao() {
return jiaZhao;
}
public void setJiaZhao(JiaZhao jiaZhao) {
this.jiaZhao = jiaZhao;
}
}
package cn.lemon.g_onetoone_2.domain;
public class JiaZhao {
private Integer id;
private String name;
private Driver driver;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Driver getDriver() {
return driver;
}
public void setDriver(Driver driver) {
this.driver = driver;
}
}
第二步:新建 Driver.hbm.xml 、JiaZhao.hbm.xml 映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-8 11:20:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="cn.lemon.g_onetoone_2.domain.Driver" table="driver">
<id name="id" type="integer">
<column name="id_" />
<generator class="native" />
</id>
<property name="name" type="string">
<column name="name_" />
</property>
<!-- 主鍵表 -->
<one-to-one name="jiaZhao" class="cn.lemon.g_onetoone_2.domain.JiaZhao"></one-to-one>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-11-8 11:20:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="cn.lemon.g_onetoone_2.domain.JiaZhao" table="jiazhao">
<id name="id" type="integer">
<column name="id_" />
<!--
foreign:引用駕駛員的主鍵作爲自己的主鍵
-->
<generator class="foreign" >
<param name="property">driver</param>
</generator>
</id>
<property name="name" type="string">
<column name="name_" />
</property>
<!-- 外鍵表
constrained:表示在添加修改時不處理這個屬性
-->
<one-to-one name="driver" class="cn.lemon.g_onetoone_2.domain.Driver" constrained="true"/>
</class>
</hibernate-mapping>
第三步:測試
package cn.lemon.g_onetoone_2.test;
import cn.lemon.d_refactor.dao.BaseDao;
import cn.lemon.g_onetoone_2.domain.Driver;
import cn.lemon.g_onetoone_2.domain.JiaZhao;
import cn.lemon.utils.HibernateUtils;
import org.junit.Test;
public class One2OneTest {
@Test
public void testCreateDb() {
HibernateUtils.getCurrentSession();
}
/**
* 添加
*/
@Test
public void test2() {
Driver u1 = new Driver();
u1.setName("張三");
Driver u2 = new Driver();
u2.setName("李四");
JiaZhao s1 = new JiaZhao();
s1.setName("駕照1");
JiaZhao s2 = new JiaZhao();
s2.setName("駕照2");
s1.setDriver(u1);
s2.setDriver(u1); //因爲張三有2個社保違反唯一約束,所以報錯。。。
BaseDao dao = new BaseDao();
dao.add(u1);
dao.add(u2);
dao.add(s1);
dao.add(s2);
}
}
十二、抓取策略(瞭解)
1、檢索方式
- 立即檢索:立即查詢,在執行查詢語句時,立即查詢所有的數據。
- 延遲檢索:延遲查詢,在執行查詢語句之後,在需要時在查詢。(延遲加載)
2、檢查策略
- 類級別檢索:當前的類的屬性獲取是否需要延遲。
- 關聯級別的檢索:當前類 關聯 另一個類是否需要延遲。
3、類級別檢索
- get:立即檢索。get方法一執行,立即查詢所有字段的數據。
- load:使用延遲檢索測試。默認情況,load方法執行後,如果只使用OID的值不進行查詢,如果要使用其他屬性值將查詢 。
Customer.hbm.xml
<class lazy="true | false">
lazy 默認值true,表示延遲檢索,默認,使用關聯數據時才檢索關聯表
設置false, 表示load使用立即檢索。查詢時立即檢索關聯數據
測試代碼
package cn.lemon.h_lazy.test;
import cn.lemon.h_lazy.domain.Customer;
import cn.lemon.utils.HibernateUtils;
import org.hibernate.Session;
import org.junit.Test;
public class ClassLazyTest {
/**
* get方法:使用立即檢索,在不打印客戶信息的情況下,也會加載數據
*/
@Test
public void test1() {
Session session = HibernateUtils.openSession();
Customer c = (Customer) session.get(Customer.class, 3);
session.close();
}
/**
* load方法:使用立即檢索
*/
@Test
public void test2() {
Session session = HibernateUtils.openSession();
Customer c = (Customer) session.load(Customer.class, 3);
session.close();//當懶加載session關閉,拋出org.hibernate.LazyInitializationException: could not initialize proxy [cn.lemon.h_lazy.domain.Customer#3] - no Session
System.out.println("---------------------------");
System.out.println(c.getName()); //使用其他屬性是才檢索數據庫數據,延遲檢索
}
}
4、關聯級別檢索—— 一對多
- 容器
<set>
提供兩個屬性:fetch、lazy- fetch:確定使用sql格式
- lazy:關聯對象是否延遲。
- fetch:數據抓取策略join、select、subselect
- select:使用多個select語句(默認值)先查詢客戶,然後根據lazy檢索策略查詢訂單
- subselect:使用子查詢,查詢多行客戶是,使用自查詢查詢訂單數據
select … from order_ where custer_id in (select… from customer ..)
5、關聯級別檢索—— 多對一
<many-to-one fetch="" lazy=""> (<one-to-one>)
- fetch取值:join、select
join:底層使用迫切左外連接
select:多條select語句 - lazy取值:false、proxy、no-proxy
false:立即
proxy:採用關聯對象 類級別檢索的策略。
訂單 關聯 客戶 (多對一)
訂單 立即獲得 客戶,需要在客戶Customer.hbm.xml <class lazy="false">
訂單 延遲獲得 客戶,需要在客戶Customer.hbm.xml <class lazy="true">