Hibernate基礎
OOD面向對象
ORM實體映射
OOP持久化操作
用戶通過框架提供的save()、update()、delete()進行增刪改等操作
用戶調用框架提供的hql或者criteria查詢語言、本地SQL查詢進行查詢操作
配置hibernate環境
第一步:
鏈接數據庫、創建數據源、把鏈接數據庫的信息寫在xml配置文件中(hibernate.cfg.xml),如用戶名、密碼、鏈
接字符串、驅動類
例(Mysql+Hibernate3.3):
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 數據庫方言,讓框架匹配其平臺 -->
<!-- org.hibernate.dialet.Oracle10gDialect -->
<!-- 上方爲oracle、下方爲mysql、且各個版本有細微差別 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 鏈接數據庫的url -->
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/lai</property>
<!-- 鏈接數據庫的用戶名 -->
<property name="connection.username">root</property>
<!-- 鏈接數據庫的密碼 -->
<property name="connection.password">root</property>
<!-- 數據庫的JDBC驅動 -->
<!-- oracle.jdbc.driver.OracleDriver -->
<!-- 上方爲oracle、下方爲mysql -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 在控制檯運行時生成的sql語句,默認沒有這一項 -->
<property name="show_sql">true</property>
<!-- 在控制檯輸出格式化的sql語句 -->
<property name="format_sql">true</property>
<!-- 在myeclipse上鍊接的工程 -->
<property name="myeclipse.connection.profile">lai</property>
<!-- 映射配置文件 -->
<mapping resource="entity/xw.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第二步:
配置映射文件,一般映射文件命名<tablename>+.hbm.xml
例(xw.hbm.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name一般表示持久化類的全限定名(包名+類名) -->
<!-- table表示持久化對應的數據庫表名 -->
<!-- catalog表示數據庫名稱 -->
<class name="id" table="xw" catalog="lai">
<!-- name表示持久化類屬性名稱 -->
<!-- type表示持久化類屬性的類型 -->
<id name="XId" type="java.lang.Integer">
<!-- 表示持久化類對應的數據庫表字段的名稱 -->
<column name="x_id" />
<!-- generator是id元素的子元素,表示主鍵生成策略,本例是assigned -->
<generator class="assigned"></generator>
<!-- 常用的生成策略有
assigned 主鍵由應用程序生成或者用戶提供,無需Hibernate干預
increment 對類型爲long、short、int的類型數據按數值順序遞增,增值爲1
identity 採用數據庫提供的主鍵生成機制,如SQL Server、DB2、Mysql支持
標識符
sequence 採用數據庫提供的sequence機制生成主鍵.如Oracle數據庫(序號)
native 由Hibernate根據底層數據庫自行判斷採用何種主鍵生成策略
-->
</id>
<!-- name表示持久化類屬性名稱 -->
<!-- type表示持久化類屬性的類型 -->
<property name="XTitle" type="java.lang.String">
<!-- 表示持久化類對應的數據庫表字段的名稱 -->
<column name="x_title" length="320" />
<!-- column元素常見的屬性有
name 表示字段的名稱
length 表示字段的長度
not-null 表示是否可以爲空
default 表示默認的值
-->
</property>
<property name="XText" type="java.lang.String">
<column name="x_text" length="3200" />
</property>
<property name="XData" type="java.lang.String">
<column name="x_data" length="320" />
</property>
<property name="XFang" type="java.lang.String">
<column name="x_fang" length="320" />
</property>
</class>
</hibernate-mapping>
第三步:
使用Hibernate完成持久化操作
先構建工具類,讓其管理session和SessionFactory HibernateSessionFactory.java
package tools;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactory {
//創建安全線程,建立本地線程對象
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
//指定配置文件
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
static {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 會話工廠創建失敗 %%%%");
e.printStackTrace();
}
}
//私有方法,限制new方法實例化
private HibernateSessionFactory() {
}
//返回會話對象session
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
//爲空時重新創建
if (sessionFactory == null) {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 會話工廠創建失敗 %%%%");
e.printStackTrace();
}
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
//關閉會話實例
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
//獲取會話工廠的方法
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
//提供路徑的方法,重新指定值
public static void setConfigFile(String configFile) {
HibernateSessionFactory.CONFIG_FILE_LOCATION = configFile;
sessionFactory = null;
}
//獲取重新指定路徑的configuration對象
public static Configuration getConfiguration() {
return configuration;
}
}
第四步:直接使用
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
Hibernate:
select
max(x_id)
from
xw
Hibernate:
insert
into
lai.xw
(x_title, x_text, x_data, x_fang, x_id)
values
(?, ?, ?, ?, ?)
控制檯可以看出,hibernate先查詢出最大id,再通過最大id進行添加
(查)
根據主鍵加載對象:
Object get(Class class,Serializable id)方法:
如果爲空,則返回null 即時加載
Object load(Class class,Serializable id)方法
如果爲空,則拋出異常:org.hibernate.ObjectNotFoundException 延遲加載(可通過lazy改變,變成立即
加載)
(增)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
(改)
xw xws = (xw) session.get(xw.class, new Integer(2));
xws.setXTitle("我是新的title");
(刪)
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
Hibernate中java對象的三種形態
瞬時狀態(Transient) 持久狀態(Persistent) 遊離狀態
(Detached)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
當前屬於瞬時狀態,它和數據庫中的數據沒有任何關聯
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
當前屬於持久狀態,session會持續跟蹤和管理這些對象,適當的時機,會提交數據,由hibernate固化到數據庫中
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
當前屬於遊離狀態,session關閉後,session實例失效,其從屬的持久化對象xws變爲遊離狀態
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
session.delete(xws); //遊離狀態下的xws,可在提交數據後,進行刪除遊離對象
HibernateSessionFactory.closeSession();
刷新緩存機制:session.flush();
該方法在tx.commit();提交事務時默認調用.無需顯示調用,主要用於刷新緩存,執行這些SQL語句,卻不提交,所
以不會生效.儲存過程.
數據更新的方法:
1、update()用於對遊離的對象進行數據庫更新操作,如沒有OID,則報錯
2、saveOrUpdate()如果傳入的參數是瞬時狀態,則調用save(),反之調用update().
瞬時時,如果存在,則報錯org.hibernate.NonUniqueObjectException
3、merge()意爲合併,如果該對象存在,則update(),反之save()
hibernate關係映射:
-------------------------------------BIN一對多關聯映射BIN----------------------------------------
outer-join:分別是true,false,auto,默認是 auto。true: 表示使用外連接抓取關聯的內容
fetch:來源查詢fetch="select"
cascade:用於指定如何操縱與當前對象關聯的其他對象
none:(默認值)忽略其他關聯對象
save-update:當調用save()、update()、saveOrUpdate()方法來保存或更新當前對象時,級聯保
存所有關聯的瞬時狀態和更新所有關聯的遊離狀態
delete:當調用delete()方法刪除當前對象時,同時級聯刪除所有關聯對象
all:包含save-updata和delete的行爲
all-delete-orphan:包含all及刪除當前對象原有關聯的"孤立"數據
inverse控制方向反轉,如果爲false,則爲一方維護,反之由多方維護
一、單向多對一關聯:
表關係如下:
部門表:id、部門name、city
create table dept(
d_id int auto_increment primary key,
d_name varchar(200),
d_loc varchar(200)
);
員工表:id、員工name、工作、外鍵
create table emp(
e_id int auto_increment,
e_name varchar(50),
e_job varchar(50),
emp_dept int,
primary key (e_id),
foreign key(emp_dept) references dept (d_id)
);
情景1、在emp類中定義了dept的實例屬性,dept中無需定義用於存放emp對象的集合屬性
emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.dept" fetch="select">
//name:持久化類的屬性名;class:持久化類的類型;fetch:來源查詢
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
</class>
</hibernate-mapping>
dept.java
private Integer DId;
private String DName;
private String DLoc;
emp.java
private Integer EId;
private dept dept;
private String EName;
private String EJob;
運行的java
dept Dept = new dept("bumen", "wuhan");
emp Emp1 = new emp(Dept, "zhangsan", "fangniu");
emp Emp2 = new emp(Dept, "lisi", "fangyang");
session.save(Dept);
session.save(Emp1);
session.save(Emp2);
運行結果:即使先save1、2,最後運行save(Dept),也能完成,多使用了updata語句,充分體現了面嚮對象語言的通
用性
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
二、單向一對多關聯:
情景2、dept中定義用於存放emp對象的集合屬性,在emp類中無需定義dept的實例屬性
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- 持久化類的屬性名 -->
<set name="emps">
<key>
<column name="emp_dept" />
<!-- 外鍵的字段名稱 -->
</key>
<one-to-many class="entity.Emp" />
<!-- 多的持久化類 -->
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private String EName;
private String EJob;
運行的java
Dept dept = new Dept("Abumen", "baijin");
Emp emp1 = new Emp("zs", "cs");
Emp emp2 = new Emp("ls", "fn");
dept.getEmps().add(emp1);
dept.getEmps().add(emp2);
session.save(dept);
session.save(emp1);
session.save(emp2);
運行結果:無論先運行那一方運行,都會多出update語句
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:update lai.emp set emp_dept=? where e_id=?
Hibernate:update lai.emp set emp_dept=? where e_id=?
三、雙向一對多關聯:
情景3、dept中定義用於存放emp對象的集合屬性,在emp類中定義dept的實例屬性(結合上兩者)
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.Dept" fetch="select">
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- inverse控制方向反轉,如果爲false,則爲一方維護,反之由多方維護 -->
<set name="emps" inverse="true" cascade="save-update">
<!-- cascade:用於指定如何操縱與當前對象關聯的其他對象
none:(默認值)忽略其他關聯對象
save-update:當調用save()、update()、saveOrUpdate()方法來保存或更新當前對象時,級聯保
存所有關聯的瞬時狀態和更新所有關聯的遊離狀態
delete:當調用delete()方法刪除當前對象時,同時級聯刪除所有關聯對象
all:包含save-updata和delete的行爲
all-delete-orphan:包含all及刪除當前對象原有關聯的"孤立"數據
-->
<key>
<column name="emp_dept" />
</key>
<one-to-many class="entity.Emp" />
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private Dept dept;
private String EName;
private String EJob;
運行的java
Dept dept = new Dept("部門1", "anhui");
Emp emp = new Emp(dept,"1", "2");
Emp emps = new Emp(dept,"1", "22222");
dept.getEmps().add(emp);
dept.getEmps().add(emps);
session.save(dept);
運行結果:添加Dept的同時,還能自動添加Emp對象
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
情景4、刪除Dept對象,同時刪除關聯的Emp對象
讓inverse="true" cascade="delete"
運行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(17));
session.delete(dept);
運行結果:刪除Dept對象,和關聯的Emp對象
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.dept where d_id=?
情景5、清空Dept對象下所有關聯的Emp對象
方式一、多方數據的外鍵列設爲null,變成孤立數據
讓inverse="false",且不設置cascade
運行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
運行結果:
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:update lai.emp set emp_dept=null where emp_dept=?
方式二、永久刪除
讓inverse="true" cascade="all-delete-orphan"
運行的java
/**清空Dept對象下所有關聯的Emp對象**/
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
/**通過Emp對象,解除雙向關聯的關係(雙向解除+刪除)**/
Emp ems = (Emp) session.get(Emp.class, new Integer(2)); //查找對應的id的ems
Dept dept = (Dept) ems.getDept(); //查找對應的部門
ems.setDept(null); //讓其變成孤立數據
dept.getEmps().remove(ems); //移除它
運行結果:Dept對象下關聯的Emp對象全部被刪除
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
-------------------------------------END一對多關聯映射END----------------------------------------
-------------------------------------BIN多對多關聯映射BIN----------------------------------------
四、多對多關聯映射(由於引入了中間表,導致多對多關聯性能不佳,避免在設計中大量使用)
表關係如下:
權限表:id、名稱
create table privilege(
p_id int auto_increment,
p_name varchar(50),
primary key (p_id)
);
角色表:id、名字
create table role(
r_id int auto_increment,
rname varchar(50),
primary key (r_id)
);
關係映射表:
create table t_privilege_role(
pid int,
rid int,
foreign key(pid) references privilege (p_id),
foreign key(rid) references role (r_id)
);
Privilege.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Privilege" table="privilege" catalog="lai">
<id name="PId" type="java.lang.Integer">
<column name="p_id" />
<generator class="increment"></generator>
</id>
<property name="PName" type="java.lang.String">
<column name="p_name" length="50" />
</property>
<!-- 維護方反轉,映射表, 在下方key和manytomany裏的對應的數據,默認位於entity.Privilege-->
<set name="TPrivilegeRoles" table="t_privilege_role" inverse="true">
<key>
<!-- 在映射表中名稱爲pid,非空 -->
<column name="pid" not-null="true" />
</key>
<!-- 多對多關聯,在entity.Role裏(set name)TPrivilegeRoles -->
<many-to-many entity-name="entity.Role">
<!-- 在映射表中的名稱爲rid,非空 -->
<column name="rid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Role" table="role" catalog="lai">
<id name="RId" type="java.lang.Integer">
<column name="r_id" />
<generator class="increment"></generator>
</id>
<property name="rname" type="java.lang.String">
<column name="rname" length="50" />
</property>
<set name="TPrivilegeRoles" table="t_privilege_role" cascade="save-update">
<key>
<column name="rid" not-null="true" />
</key>
<many-to-many entity-name="entity.Privilege">
<column name="pid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Privilege.java
private Integer PId;
private String PName;
private Set TPrivilegeRoles = new HashSet(0);
Role.java
private Integer RId;
private String rname;
private Set TPrivilegeRoles = new HashSet(0);
運行的java
Role role1 = new Role("會計");
Role role2 = new Role("人事");
Privilege privilege1 = new Privilege("員工信息表");
Privilege privilege2 = new Privilege("查詢工資表");
role1.getTPrivilegeRoles().add(privilege2);
role2.getTPrivilegeRoles().add(privilege1);
session.save(role1);
session.save(role2);
結果:
mysql> select * from t_privilege_role;
+------+------+
| pid | rid |
+------+------+
| 1 | 1 |
| 2 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from privilege;
+------+-----------------+
| p_id | p_name |
+------+-----------------+
| 1 | 鏌ヨ宸ヨ祫琛? |
| 2 | 鍛樺伐淇℃伅琛? |
+------+-----------------+
2 rows in set (0.00 sec)
mysql> select * from role;
+------+--------+
| r_id | rname |
+------+--------+
| 1 | 浼氳 |
| 2 | 浜轟簨 |
+------+--------+
-------------------------------------END多對多關聯映射END----------------------------------------
五、一對一關聯映射
表關係如下:
-------------------------------------BIN外鍵映射BIN----------------------------------------
方法1、外鍵映射
公民表:id、名字、年齡、男女、歸屬地
create table Citizenl(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id)
);
身份證表:id、外鍵、身份證號
create table IDCardl(
I_id int auto_increment,
c_id int,
I_idno varchar(18) unique,
primary key (I_id),
foreign key(c_id) references Citizenl (c_id)
);
Citizenl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizenl" table="citizenl" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<generator class="increment"></generator>
</id>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
<!-- 將entity.Citizenl內idcardls與entity.Idcardl裏citizenl關聯 -->
<one-to-one name="idcardls" class="entity.Idcardl" property-ref="citizenl"></one-to-one>
</class>
</hibernate-mapping>
IDCardl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcardl" table="idcardl" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment" />
</id>
<!-- 多對一,entity.Idcardl中citizenl,與entity.Citizenl關聯 -->
<many-to-one name="citizenl" class="entity.Citizenl" fetch="select" cascade="all" >
<column name="c_id" unique="true" />
</many-to-one>
<property name="IIdno" type="java.lang.String" not-null="true">
<column name="I_idno" length="18" />
</property>
</class>
</hibernate-mapping>
Citizenl.java
private Integer CId;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
private Set<Idcardl> idcardls = new HashSet<Idcardl> (0);
IDCardl.java
private Integer IId;
private Citizenl citizenl;
private String IIdno;
運行的java
Citizenl cit = new Citizenl("張三", 12, "男", "東莞");
Idcardl idc = new Idcardl("421102938271918231");
cit.getIdcardls().add(idc);
idc.setCitizenl(cit);
session.save(idc);
運行結果:
mysql> select * from idcardl;
+------+------+--------------------+
| I_id | c_id | I_idno |
+------+------+--------------------+
| 1 | 1 | 421102938271918231 |
+------+------+--------------------+
1 row in set (0.00 sec)
mysql> select * from Citizenl;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | 寮犱笁 | 12 | 鐢? | 涓滆帪 |
+------+--------+-------+----------+-----------+
1 row in set (0.00 sec)
-------------------------------------END外鍵映射END----------------------------------------
-------------------------------------BIN主鍵映射BIN----------------------------------------
方法2、主鍵映射
公民表:id(主鍵加外鍵)、名字、年齡、男女、歸屬地
create table Citizen2(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id),
foreign key(c_id) references IDCard2 (I_id)
);
身份證表:id、身份證號
create table IDCard2(
I_id int auto_increment,
I_idno varchar(18) unique,
primary key (I_id)
);
Citizen2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizen2" table="citizen2" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<!-- 根據xxx的外鍵生成主鍵 -->
<generator class="foreign">
<param name="property">idcard2</param>
</generator>
</id>
<!-- 當前主鍵存在一個約束 constrained="true" -->
<!-- 將兩個類關聯起來 -->
<one-to-one name="idcard2" class="entity.Idcard2" constrained="true" >
</one-to-one>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
</class>
</hibernate-mapping>
IDCard2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcard2" table="idcard2" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment"></generator>
</id>
<property name="IIdno" type="java.lang.String">
<column name="I_idno" length="18" unique="true" />
</property>
<!-- 關聯類 -->
<one-to-one name="citizen2" class="entity.Citizen2" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Citizen2.java
private Integer CId;
private Idcard2 idcard2;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
Idcard2.java
private Integer IId;
private String IIdno;
private Citizen2 citizen2;
運行的java代碼
Idcard2 id = new Idcard2("1111111321111");
Citizen2 ci = new Citizen2("mie", 18, "男", "日本");
id.setCitizen2(ci);
ci.setIdcard2(id);
session.save(id);
運行結果:
mysql> select * from IDCard2;
+------+----------------+
| I_id | I_idno |
+------+----------------+
| 2 | 1111111321111 |
| 1 | 11211111321111 |
+------+----------------+
2 rows in set (0.00 sec)
mysql> select * from Citizen2;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | mie | 18 | 鐢? | 鏃ユ湰 |
| 2 | mie | 18 | 鐢? | 鏃ユ湰 |
+------+--------+-------+----------+-----------+
2 rows in set (0.00 sec)
-------------------------------------END主鍵映射END----------------------------------------
Hibernate數據加載
加載策略:lazy
類級別:<class ... lazy="true">(默認)true延遲加載||false立即加載
一對多關聯級別:<set ... lazy="true">(默認)true延遲加載||false立即加載||extra增強延遲加載
多對一關聯級別:<many-to-one ... lazy="proxy">(默認)proxy延遲加載||no-proxy無代理延遲加載||false立
即加載
多對多關聯級別:<many-to-many ... lazy="proxy" />(默認)proxy延遲加載||false立即加載
利用load方法加載對象,不會訪問表中的select語句,會生成一個對應表的代理類,代理類擁有一個屬性,主鍵。
Dept dept = (Dept)session.load(Dept.class,new Interger(10)); //此時的dept就屬於一個代理實例
在session關閉後,對應的代理實例就無法初始化
如果一對多中set標籤中採用的是立即加載,那麼,對一操作時,同時也會加載多,造成了性能的耗費
只有當dept初始化時,纔會訪問數據庫加載,調用其Set集合:
Set<Emp> emps = dept.getEmps();
Interator it = emps.interator()、size()、isEmpty()、contains();
Hibernate.initialize(emps); //初始化
當使用增強延遲加載的時候:他不會查詢所有的emp對象,他會比較聰明的發送聚合函數查詢數據的記錄數,起到
性能優化的作用
Dept dept = (Dept)session.load(Dept.class,new Interger(10));
Set<Emp> emps = dept.getEmps();
int Count = emps.size();
無代理延遲加載,是指只有遇到代理實例,纔開始訪問數據庫,加載程序
立即加載,逐行加載,賊耗性能
OpenSessionInView模式
在視圖層打開session:用戶每次請求過程中都保持一個Session對象打開
配置流程:
配置文件中加入
<!-- session綁定到當前線程OpenSessionIn View -->
<property name="hibernate.current_session_context_class">thread</property>
創建過濾器類
public class OpenSessionInViewFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
Transaction tx = null;
try {
Session session = HibernateSessionFactory.getSessionFactory
().getCurrentSession();
tx=session.beginTransaction();
chain.doFilter(request, response);
//返回響應時提交事務
tx.commit();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
tx.rollback();
}finally{
HibernateSessionFactory.closeSession();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置上面的filter
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>tools.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
實際調用的時候:
//通過id返回該對象的代理類
public class DeptDaoImpl {
public Citizen2 getCitizen2(Integer id){
//這裏獲取的Session對象就是OpenSessionInViewFilter過濾器中打開的session,無需關閉session,
回到過濾器中會自己關閉
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession
();
//通過getCurrentSession創建的session會在事務提交後,或事物回滾,自動關閉
return (Citizen2) session .get(Citizen2.class, id);
}
}
Hibernate查詢
一、HQL:Hibernate Query Language 語法與SQL類似,但它是面向對象的,SQL是關係型數據
[select/delete/update...][from 實體類][where...][group by ...][having...][order by ...]
例:
String hql = "from Citizen2"; //編寫hql語句
Query query = session.createQuery(hql); //創建Query對象
List<Citizen2> idcard2 = query.list(); //得到封裝好的結果
System.out.println(idcard2.size()); //打印個數
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAge()); //打印輸出對應的屬性
}
解析:from Citizen2.其中select部分可以省略,from等關鍵詞可以大小寫隨意寫,但是Citizen2只能這麼些,這
表示一個類名.
不允許有大小寫的出入,完整的寫法,select e from Citizen2 as e,as可以省略,不能寫成select * from
Citizen2 e.其中e
表示對象名稱,表示查詢整個對象
/**執行時遇到了錯誤antlr.collections.AST.getLine()異常,原因是struts中的antlr2.x過時,和hibernate裏
的antlr2.7.6衝突**/
/**解決方法:刪除Myeclipse文件夾下/configuration/org.eclipse.osgi下刪除,再在/plugins/下搜索
*struts*,用壓縮包打開刪除掉,防止自動生成**/
帶條件查詢:
String hql = "from Citizen2 where CAge=?"; //條件語句,這裏查詢的是對象裏的參
數,不是數據庫裏的
//from Citizen2 e where e.CAge=?也行
Query query = session.createQuery(hql); //創建Query對象
query.setInteger(0, 18); //填充條件,第一個問號,jdbc從1開始
,hql從0開始
//setParameter可填充任意形式的字符,int,String
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAddress());
}
模糊查詢(鏈式寫法):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString(0,"%運%"),setInteger(1,20).list();
也可以用名字佔位(先後順序可以打亂,參數前面加":"):
String hql = "from Citizen2 where CName like :name and CAge> :age ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString("name","%運%"),setInteger("age",20).list();
主鍵查詢(你確定只有一個結果值時):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
Citizen2 cit = query.getString(0,"%運%"),setInteger(1,20).uniqueResult();
投影查詢(說的辣麼高級,其實就是一般的查詢列,最後用Object[]封裝而已,類似數組調用):
String hql = "select CId,CName from Citizen2";
Query query = session.createQuery(hql);
List<Object[]> idcard2 = query.list();
for (Object[] obj : idcard2) {
System.out.println(obj[0]+""+obj[1]);
}
返回的是部分值,和上面不同的是List<e>類型,弊端在於需要創建對應的構造函數(new ...)
String hql = "select new Citizen2(CId,CName) from Citizen2";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
排序(默認情況下,按照升序順序排序):下面是降序排序(order by e.CId desc)
String hql = "select e from Citizen2 e order by e.CId desc";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
分頁(setFirstResult(n),setMaxResults(m))
String hql ="from Citizen2";
Query query = session.createQuery(hql);
//setFirstResult(0)設置第一條記錄的開始位置,這裏從0開始.setMaxResults(5):設置每頁
顯示的大小
query.setFirstResult(0).setMaxResults(5);//查詢結果1,2,3,4,5
List<Citizen2> cit = query.list();
for (Citizen2 citizen2 : cit) {
System.out.println(citizen2.getCId());
}
聚合函數(MYSQL中與HQL中對比)
mysql> select count(*) from Citizen2; String hql ="select count(e) from Citizen2 e";
+----------+ //這裏第一個e可以換成*或者其他參數,如CId···
| count(*) | Query query = session.createQuery(hql);
+----------+
| 10 | Long count = (Long)query.uniqueResult();
+----------+
1 row in set (0.00 sec) System.out.println(count);結果都是10
mysql> select min(c_id) from Citizen2; String hql ="select max(CId),min(CId),avg(CId)
from Citizen2 e";
+-----------+
| min(c_id) | Query query = session.createQuery(hql);
+-----------+
| 1 | Object[] count = (Object[])query.uniqueResult();
+-----------+
1 row in set (0.00 sec) for (int i = 0; i < count.length; i++) {
System.out.println(count[i]+"\t");
}
內鏈接:inner join||join
迫切內鏈接:inner join fetch||join fetch
左鏈接(迫切):left outer join (fetch)||left join (fetch)
右鏈接(迫切):right outer join (fetch) || right join
當然HQL還支持分組查詢、子查詢、表連接(拼接)等,不細細講了
Double d = 2.1111;//在製作商場網站時,需要製作Double調換,將Double轉換精度
new DecimalFormat("0.000").format(d);
二、QBC:Query By Criteria 是一組API提供了完全面向對象的接口、類、方法
專用於對SQL不太熟悉的開發者,主要使用到了Criteria對象,使用add()方法加入查詢條件,使用list()方法執行
查詢語句.設置條件,
用的比較多的是Restrictions類,而不是Expression類
例子:查詢該表
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:排序(傳入的一樣是類中字段,不是表中字段)
Criteria crit = session.createCriteria(Citizen2.class);
crit.addOrder(Order.desc("CId"));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:分頁查詢(和HQL的分頁類似,使用了setFirstResult()、setMaxResults()方法)
Criteria crit = session.createCriteria(Citizen2.class);
crit.setFirstResult(0).setMaxResults(3);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:條件查詢(年齡等於22的)
Criteria crit = session.createCriteria(Citizen2.class);
crit.add(Restrictions.eq("CAge", 22));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
Restrictions查詢常用方法:
Restrictions.eq() 對應SQL的等於
Restrictions.allEq() 使用Map,對應多個相等的值對比
Restrictions.gt() 對應的SQL大於
Restrictions.ge() 對應的SQL大於等於
Restrictions.lt() 對應的SQL小於
Restrictions.le() 對應的小於等於
Restrictions.between() 對應的between子句
Restrictions.like() 對應的SQL的like子句
Restrictions.in() 對應的SQL的in子句
Restrictions.and() 對應的SQL的and子句
Restrictions.or() 對應的SQL的or子句
Restrictions.not() 對應的SQL的not子句
Restrictions.disjunction() 針對三個及三個以上的or或and條件查詢(如下:)
Criteria crit = session.createCriteria(Citizen2.class).add(Restrictions.disjunction().add
(Restrictions.gt("",""))
.add(Restrictions.ge("","")).add(Restrictions.eq("","")));
Restrictions.conjunction() 針對三個或者三個以上的and操作,將上述改成這個方法即可
Example查詢(主要用於查詢條件較多的時候,會把查詢條件封裝成一個類):
例子:
Citizen2 cit = new Citizen2();
cit.setCAge(22);
cit.setCName("樂運來");
cit.setCAddress("武漢市");
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.add(Example.create(cit)).list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCId()+citizen2.getCAddress());
}
//List<Citizen2> list = crit.add(Example.create(cit).excludeProperty
("CName")).list();
還可以後面追加方法,將一些情況排除(上述添加的是excludeProperty("xxx"))
excludeZeroes(); 排除值爲0的屬性
excludePreperty("xxx") 排除xxx的屬性的條件
ignoreCase() 忽略大小寫比較
enableLike() 使用模糊查詢
如果要查詢所屬部門是SALES的員工有哪些,因爲部門名字是在dept表中,而結果是在emp表的內容,所以需要使用
到表連接查詢:
Criteria crit = session.createCriteria(Emp.class).createCriteria("dept").add(Restrictions.eq
("d_name","SALES"));
第二次可以理解爲表連接,查詢的是Emp數據,條件是dept裏的d_name等於SALES
同理也可以使用主鍵和外鍵查詢:session.createCriteria(Emp.class).add(Restrictions.eq
("dept.d_id",10));
Projections類的聚合函數
avg() 平均值
count() 出現的次數
countDistinct() 不重複值的數量
max() 最大值
min() 最小值
sum() 總和
例子:計算出現次數
Criteria crit = session.createCriteria(Citizen2.class);
crit.setProjection(Projections.count("CAge"));
Integer count = (Integer) crit.uniqueResult();
System.out.println(count);
例子:當計算的比較多的時候,利用ProjectionList裝進去
Criteria crit = session.createCriteria(Citizen2.class);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.max("CAge"));
projList.add(Projections.min("CAge"));
crit.setProjection(projList);
Object[] count = (Object[]) crit.uniqueResult();
System.out.println(count[0]+""+count[1]);
DetachedCriteria的使用(分離的Criteria,可用於不同條件下的查詢,複用性高)
//創建DetachedCriteria查詢規則,通過forClass方法創建
DetachedCriteria dc = DetachedCriteria.forClass(Citizen2.class);
//添加條件
dc.add(Restrictions.between("CAge", 18, 20));
dc.add(Restrictions.ilike("CName", "%i%"));
//開啓第一個會話
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
//通過DetachedCriteria得到Criteria對象,參與活動的是session
Criteria crit = dc.getExecutableCriteria(session);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCAge()+citizen2.getCId
()+citizen2.getCAddress());
}
tx.commit();
//關閉第一個會話
HibernateSessionFactory.closeSession();
//重新打開一個會話
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 = session2.beginTransaction();
//檢測是否是同一個會話,false表示不是一個
System.out.println(session==session2);
//通過DetachedCriteria得到Criteria對象,參與活動的是session
Criteria cri2 = dc.getExecutableCriteria(session2);
cri2.setProjection(Projections.sum("CAge"));
//再次得到查詢
Integer ob = (Integer)cri2.uniqueResult();
System.out.println(ob);
//關閉第二個會話
tx2.commit();
HibernateSessionFactory.closeSession();
當然,還可以用於子查詢
DetachedCriteria avg = DetachedCriteria.forClass(Emp.class).setProjection
(Property.forName("sal").avg());
//查詢工資高於平均工資的員工
List<Emp> emps = session.createCriteria(Emp.class).add(Property.forName('sal').gt
(avg)).list();
三、SQL:Structured Query Language 這是Hibernate提供的原生的SQL查詢方式,支持使用SQL語句的
方式查詢數據庫
//查詢表的全部參數,利用addEntity(Citizen2.class)方法轉換爲實體對象
Query q = session.createSQLQuery("select * from citizen2").addEntity
(Citizen2.class);
//.addScalar("c_id",Integer);用於查詢結果和標量值
List<Citizen2> n = q.list();
for (Citizen2 citizen2 : n) {
System.out.println(citizen2.getCName());
}
ORM實體映射
OOP持久化操作
用戶通過框架提供的save()、update()、delete()進行增刪改等操作
用戶調用框架提供的hql或者criteria查詢語言、本地SQL查詢進行查詢操作
配置hibernate環境
第一步:
鏈接數據庫、創建數據源、把鏈接數據庫的信息寫在xml配置文件中(hibernate.cfg.xml),如用戶名、密碼、鏈
接字符串、驅動類
例(Mysql+Hibernate3.3):
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 數據庫方言,讓框架匹配其平臺 -->
<!-- org.hibernate.dialet.Oracle10gDialect -->
<!-- 上方爲oracle、下方爲mysql、且各個版本有細微差別 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 鏈接數據庫的url -->
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/lai</property>
<!-- 鏈接數據庫的用戶名 -->
<property name="connection.username">root</property>
<!-- 鏈接數據庫的密碼 -->
<property name="connection.password">root</property>
<!-- 數據庫的JDBC驅動 -->
<!-- oracle.jdbc.driver.OracleDriver -->
<!-- 上方爲oracle、下方爲mysql -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 在控制檯運行時生成的sql語句,默認沒有這一項 -->
<property name="show_sql">true</property>
<!-- 在控制檯輸出格式化的sql語句 -->
<property name="format_sql">true</property>
<!-- 在myeclipse上鍊接的工程 -->
<property name="myeclipse.connection.profile">lai</property>
<!-- 映射配置文件 -->
<mapping resource="entity/xw.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第二步:
配置映射文件,一般映射文件命名<tablename>+.hbm.xml
例(xw.hbm.xml):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name一般表示持久化類的全限定名(包名+類名) -->
<!-- table表示持久化對應的數據庫表名 -->
<!-- catalog表示數據庫名稱 -->
<class name="id" table="xw" catalog="lai">
<!-- name表示持久化類屬性名稱 -->
<!-- type表示持久化類屬性的類型 -->
<id name="XId" type="java.lang.Integer">
<!-- 表示持久化類對應的數據庫表字段的名稱 -->
<column name="x_id" />
<!-- generator是id元素的子元素,表示主鍵生成策略,本例是assigned -->
<generator class="assigned"></generator>
<!-- 常用的生成策略有
assigned 主鍵由應用程序生成或者用戶提供,無需Hibernate干預
increment 對類型爲long、short、int的類型數據按數值順序遞增,增值爲1
identity 採用數據庫提供的主鍵生成機制,如SQL Server、DB2、Mysql支持
標識符
sequence 採用數據庫提供的sequence機制生成主鍵.如Oracle數據庫(序號)
native 由Hibernate根據底層數據庫自行判斷採用何種主鍵生成策略
-->
</id>
<!-- name表示持久化類屬性名稱 -->
<!-- type表示持久化類屬性的類型 -->
<property name="XTitle" type="java.lang.String">
<!-- 表示持久化類對應的數據庫表字段的名稱 -->
<column name="x_title" length="320" />
<!-- column元素常見的屬性有
name 表示字段的名稱
length 表示字段的長度
not-null 表示是否可以爲空
default 表示默認的值
-->
</property>
<property name="XText" type="java.lang.String">
<column name="x_text" length="3200" />
</property>
<property name="XData" type="java.lang.String">
<column name="x_data" length="320" />
</property>
<property name="XFang" type="java.lang.String">
<column name="x_fang" length="320" />
</property>
</class>
</hibernate-mapping>
第三步:
使用Hibernate完成持久化操作
先構建工具類,讓其管理session和SessionFactory HibernateSessionFactory.java
package tools;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactory {
//創建安全線程,建立本地線程對象
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
//指定配置文件
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
static {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 會話工廠創建失敗 %%%%");
e.printStackTrace();
}
}
//私有方法,限制new方法實例化
private HibernateSessionFactory() {
}
//返回會話對象session
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
//爲空時重新創建
if (sessionFactory == null) {
try {
configuration.configure(CONFIG_FILE_LOCATION);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% 會話工廠創建失敗 %%%%");
e.printStackTrace();
}
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
//關閉會話實例
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
//獲取會話工廠的方法
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
//提供路徑的方法,重新指定值
public static void setConfigFile(String configFile) {
HibernateSessionFactory.CONFIG_FILE_LOCATION = configFile;
sessionFactory = null;
}
//獲取重新指定路徑的configuration對象
public static Configuration getConfiguration() {
return configuration;
}
}
第四步:直接使用
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
Hibernate:
select
max(x_id)
from
xw
Hibernate:
insert
into
lai.xw
(x_title, x_text, x_data, x_fang, x_id)
values
(?, ?, ?, ?, ?)
控制檯可以看出,hibernate先查詢出最大id,再通過最大id進行添加
(查)
根據主鍵加載對象:
Object get(Class class,Serializable id)方法:
如果爲空,則返回null 即時加載
Object load(Class class,Serializable id)方法
如果爲空,則拋出異常:org.hibernate.ObjectNotFoundException 延遲加載(可通過lazy改變,變成立即
加載)
(增)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
(改)
xw xws = (xw) session.get(xw.class, new Integer(2));
xws.setXTitle("我是新的title");
(刪)
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
Hibernate中java對象的三種形態
瞬時狀態(Transient) 持久狀態(Persistent) 遊離狀態
(Detached)
xw xws = new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
當前屬於瞬時狀態,它和數據庫中的數據沒有任何關聯
xw xws = (xw) session.get(xw.class, new Integer(2));
session.delete(xws);
當前屬於持久狀態,session會持續跟蹤和管理這些對象,適當的時機,會提交數據,由hibernate固化到數據庫中
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
HibernateSessionFactory.closeSession();
當前屬於遊離狀態,session關閉後,session實例失效,其從屬的持久化對象xws變爲遊離狀態
xw xws= new xw(null, "奇了", "hibernate", "可以添加", "訪問量");
session.save(xws);
tx.commit();
session.delete(xws); //遊離狀態下的xws,可在提交數據後,進行刪除遊離對象
HibernateSessionFactory.closeSession();
刷新緩存機制:session.flush();
該方法在tx.commit();提交事務時默認調用.無需顯示調用,主要用於刷新緩存,執行這些SQL語句,卻不提交,所
以不會生效.儲存過程.
數據更新的方法:
1、update()用於對遊離的對象進行數據庫更新操作,如沒有OID,則報錯
2、saveOrUpdate()如果傳入的參數是瞬時狀態,則調用save(),反之調用update().
瞬時時,如果存在,則報錯org.hibernate.NonUniqueObjectException
3、merge()意爲合併,如果該對象存在,則update(),反之save()
hibernate關係映射:
-------------------------------------BIN一對多關聯映射BIN----------------------------------------
outer-join:分別是true,false,auto,默認是 auto。true: 表示使用外連接抓取關聯的內容
fetch:來源查詢fetch="select"
cascade:用於指定如何操縱與當前對象關聯的其他對象
none:(默認值)忽略其他關聯對象
save-update:當調用save()、update()、saveOrUpdate()方法來保存或更新當前對象時,級聯保
存所有關聯的瞬時狀態和更新所有關聯的遊離狀態
delete:當調用delete()方法刪除當前對象時,同時級聯刪除所有關聯對象
all:包含save-updata和delete的行爲
all-delete-orphan:包含all及刪除當前對象原有關聯的"孤立"數據
inverse控制方向反轉,如果爲false,則爲一方維護,反之由多方維護
一、單向多對一關聯:
表關係如下:
部門表:id、部門name、city
create table dept(
d_id int auto_increment primary key,
d_name varchar(200),
d_loc varchar(200)
);
員工表:id、員工name、工作、外鍵
create table emp(
e_id int auto_increment,
e_name varchar(50),
e_job varchar(50),
emp_dept int,
primary key (e_id),
foreign key(emp_dept) references dept (d_id)
);
情景1、在emp類中定義了dept的實例屬性,dept中無需定義用於存放emp對象的集合屬性
emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.dept" fetch="select">
//name:持久化類的屬性名;class:持久化類的類型;fetch:來源查詢
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
</class>
</hibernate-mapping>
dept.java
private Integer DId;
private String DName;
private String DLoc;
emp.java
private Integer EId;
private dept dept;
private String EName;
private String EJob;
運行的java
dept Dept = new dept("bumen", "wuhan");
emp Emp1 = new emp(Dept, "zhangsan", "fangniu");
emp Emp2 = new emp(Dept, "lisi", "fangyang");
session.save(Dept);
session.save(Emp1);
session.save(Emp2);
運行結果:即使先save1、2,最後運行save(Dept),也能完成,多使用了updata語句,充分體現了面嚮對象語言的通
用性
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
Hibernate:insert into lai.emp (emp_dept, e_name, e_job, e_id) values (?, ?, ?, ?)
二、單向一對多關聯:
情景2、dept中定義用於存放emp對象的集合屬性,在emp類中無需定義dept的實例屬性
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- 持久化類的屬性名 -->
<set name="emps">
<key>
<column name="emp_dept" />
<!-- 外鍵的字段名稱 -->
</key>
<one-to-many class="entity.Emp" />
<!-- 多的持久化類 -->
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private String EName;
private String EJob;
運行的java
Dept dept = new Dept("Abumen", "baijin");
Emp emp1 = new Emp("zs", "cs");
Emp emp2 = new Emp("ls", "fn");
dept.getEmps().add(emp1);
dept.getEmps().add(emp2);
session.save(dept);
session.save(emp1);
session.save(emp2);
運行結果:無論先運行那一方運行,都會多出update語句
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:update lai.emp set emp_dept=? where e_id=?
Hibernate:update lai.emp set emp_dept=? where e_id=?
三、雙向一對多關聯:
情景3、dept中定義用於存放emp對象的集合屬性,在emp類中定義dept的實例屬性(結合上兩者)
Emp.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Emp" table="emp" catalog="lai">
<id name="EId" type="java.lang.Integer">
<column name="e_id" />
<generator class="increment"></generator>
</id>
<many-to-one name="dept" class="entity.Dept" fetch="select">
<column name="emp_dept" />
</many-to-one>
<property name="EName" type="java.lang.String">
<column name="e_name" length="50" />
</property>
<property name="EJob" type="java.lang.String">
<column name="e_job" length="50" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Dept" table="dept" catalog="lai">
<id name="DId" type="java.lang.Integer">
<column name="d_id" />
<generator class="increment"></generator>
</id>
<property name="DName" type="java.lang.String">
<column name="d_name" length="200" />
</property>
<property name="DLoc" type="java.lang.String">
<column name="d_loc" length="200" />
</property>
<!-- inverse控制方向反轉,如果爲false,則爲一方維護,反之由多方維護 -->
<set name="emps" inverse="true" cascade="save-update">
<!-- cascade:用於指定如何操縱與當前對象關聯的其他對象
none:(默認值)忽略其他關聯對象
save-update:當調用save()、update()、saveOrUpdate()方法來保存或更新當前對象時,級聯保
存所有關聯的瞬時狀態和更新所有關聯的遊離狀態
delete:當調用delete()方法刪除當前對象時,同時級聯刪除所有關聯對象
all:包含save-updata和delete的行爲
all-delete-orphan:包含all及刪除當前對象原有關聯的"孤立"數據
-->
<key>
<column name="emp_dept" />
</key>
<one-to-many class="entity.Emp" />
</set>
</class>
</hibernate-mapping>
Dept.java
private Integer DId;
private String DName;
private String DLoc;
private Set<Emp> emps = new HashSet<Emp>(0);
Emp.java
private Integer EId;
private Dept dept;
private String EName;
private String EJob;
運行的java
Dept dept = new Dept("部門1", "anhui");
Emp emp = new Emp(dept,"1", "2");
Emp emps = new Emp(dept,"1", "22222");
dept.getEmps().add(emp);
dept.getEmps().add(emps);
session.save(dept);
運行結果:添加Dept的同時,還能自動添加Emp對象
Hibernate:select max(d_id) from dept
Hibernate:select max(e_id) from emp
Hibernate:insert into lai.dept (d_name, d_loc, d_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
Hibernate:insert into lai.emp (e_name, e_job, e_id) values (?, ?, ?)
情景4、刪除Dept對象,同時刪除關聯的Emp對象
讓inverse="true" cascade="delete"
運行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(17));
session.delete(dept);
運行結果:刪除Dept對象,和關聯的Emp對象
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.emp where e_id=?
Hibernate:delete from lai.dept where d_id=?
情景5、清空Dept對象下所有關聯的Emp對象
方式一、多方數據的外鍵列設爲null,變成孤立數據
讓inverse="false",且不設置cascade
運行的java
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
運行結果:
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:update lai.emp set emp_dept=null where emp_dept=?
方式二、永久刪除
讓inverse="true" cascade="all-delete-orphan"
運行的java
/**清空Dept對象下所有關聯的Emp對象**/
Dept dept = (Dept) session.load(Dept.class, new Integer(27));
dept.getEmps().clear();
/**通過Emp對象,解除雙向關聯的關係(雙向解除+刪除)**/
Emp ems = (Emp) session.get(Emp.class, new Integer(2)); //查找對應的id的ems
Dept dept = (Dept) ems.getDept(); //查找對應的部門
ems.setDept(null); //讓其變成孤立數據
dept.getEmps().remove(ems); //移除它
運行結果:Dept對象下關聯的Emp對象全部被刪除
Hibernate:select dept0_.d_id as d1_0_0_,dept0_.d_name as d2_0_0_,dept0_.d_loc as
d3_0_0_ from lai.dept dept0_ where dept0_.d_id=?
Hibernate:select emps0_.emp_dept as emp2_1_,emps0_.e_id as e1_1_,emps0_.e_id as e1_1_0_,
emps0_.emp_dept as emp2_1_0_,emps0_.e_name as e3_1_0_,emps0_.e_job as e4_1_0_ from
lai.emp emps0_ where emps0_.emp_dept=?
Hibernate:delete from lai.emp where e_id=?
-------------------------------------END一對多關聯映射END----------------------------------------
-------------------------------------BIN多對多關聯映射BIN----------------------------------------
四、多對多關聯映射(由於引入了中間表,導致多對多關聯性能不佳,避免在設計中大量使用)
表關係如下:
權限表:id、名稱
create table privilege(
p_id int auto_increment,
p_name varchar(50),
primary key (p_id)
);
角色表:id、名字
create table role(
r_id int auto_increment,
rname varchar(50),
primary key (r_id)
);
關係映射表:
create table t_privilege_role(
pid int,
rid int,
foreign key(pid) references privilege (p_id),
foreign key(rid) references role (r_id)
);
Privilege.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Privilege" table="privilege" catalog="lai">
<id name="PId" type="java.lang.Integer">
<column name="p_id" />
<generator class="increment"></generator>
</id>
<property name="PName" type="java.lang.String">
<column name="p_name" length="50" />
</property>
<!-- 維護方反轉,映射表, 在下方key和manytomany裏的對應的數據,默認位於entity.Privilege-->
<set name="TPrivilegeRoles" table="t_privilege_role" inverse="true">
<key>
<!-- 在映射表中名稱爲pid,非空 -->
<column name="pid" not-null="true" />
</key>
<!-- 多對多關聯,在entity.Role裏(set name)TPrivilegeRoles -->
<many-to-many entity-name="entity.Role">
<!-- 在映射表中的名稱爲rid,非空 -->
<column name="rid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Role" table="role" catalog="lai">
<id name="RId" type="java.lang.Integer">
<column name="r_id" />
<generator class="increment"></generator>
</id>
<property name="rname" type="java.lang.String">
<column name="rname" length="50" />
</property>
<set name="TPrivilegeRoles" table="t_privilege_role" cascade="save-update">
<key>
<column name="rid" not-null="true" />
</key>
<many-to-many entity-name="entity.Privilege">
<column name="pid" not-null="true"></column>
</many-to-many>
</set>
</class>
</hibernate-mapping>
Privilege.java
private Integer PId;
private String PName;
private Set TPrivilegeRoles = new HashSet(0);
Role.java
private Integer RId;
private String rname;
private Set TPrivilegeRoles = new HashSet(0);
運行的java
Role role1 = new Role("會計");
Role role2 = new Role("人事");
Privilege privilege1 = new Privilege("員工信息表");
Privilege privilege2 = new Privilege("查詢工資表");
role1.getTPrivilegeRoles().add(privilege2);
role2.getTPrivilegeRoles().add(privilege1);
session.save(role1);
session.save(role2);
結果:
mysql> select * from t_privilege_role;
+------+------+
| pid | rid |
+------+------+
| 1 | 1 |
| 2 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from privilege;
+------+-----------------+
| p_id | p_name |
+------+-----------------+
| 1 | 鏌ヨ宸ヨ祫琛? |
| 2 | 鍛樺伐淇℃伅琛? |
+------+-----------------+
2 rows in set (0.00 sec)
mysql> select * from role;
+------+--------+
| r_id | rname |
+------+--------+
| 1 | 浼氳 |
| 2 | 浜轟簨 |
+------+--------+
-------------------------------------END多對多關聯映射END----------------------------------------
五、一對一關聯映射
表關係如下:
-------------------------------------BIN外鍵映射BIN----------------------------------------
方法1、外鍵映射
公民表:id、名字、年齡、男女、歸屬地
create table Citizenl(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id)
);
身份證表:id、外鍵、身份證號
create table IDCardl(
I_id int auto_increment,
c_id int,
I_idno varchar(18) unique,
primary key (I_id),
foreign key(c_id) references Citizenl (c_id)
);
Citizenl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizenl" table="citizenl" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<generator class="increment"></generator>
</id>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
<!-- 將entity.Citizenl內idcardls與entity.Idcardl裏citizenl關聯 -->
<one-to-one name="idcardls" class="entity.Idcardl" property-ref="citizenl"></one-to-one>
</class>
</hibernate-mapping>
IDCardl.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcardl" table="idcardl" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment" />
</id>
<!-- 多對一,entity.Idcardl中citizenl,與entity.Citizenl關聯 -->
<many-to-one name="citizenl" class="entity.Citizenl" fetch="select" cascade="all" >
<column name="c_id" unique="true" />
</many-to-one>
<property name="IIdno" type="java.lang.String" not-null="true">
<column name="I_idno" length="18" />
</property>
</class>
</hibernate-mapping>
Citizenl.java
private Integer CId;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
private Set<Idcardl> idcardls = new HashSet<Idcardl> (0);
IDCardl.java
private Integer IId;
private Citizenl citizenl;
private String IIdno;
運行的java
Citizenl cit = new Citizenl("張三", 12, "男", "東莞");
Idcardl idc = new Idcardl("421102938271918231");
cit.getIdcardls().add(idc);
idc.setCitizenl(cit);
session.save(idc);
運行結果:
mysql> select * from idcardl;
+------+------+--------------------+
| I_id | c_id | I_idno |
+------+------+--------------------+
| 1 | 1 | 421102938271918231 |
+------+------+--------------------+
1 row in set (0.00 sec)
mysql> select * from Citizenl;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | 寮犱笁 | 12 | 鐢? | 涓滆帪 |
+------+--------+-------+----------+-----------+
1 row in set (0.00 sec)
-------------------------------------END外鍵映射END----------------------------------------
-------------------------------------BIN主鍵映射BIN----------------------------------------
方法2、主鍵映射
公民表:id(主鍵加外鍵)、名字、年齡、男女、歸屬地
create table Citizen2(
c_id int auto_increment,
c_name varchar(30),
c_age int,
c_gender varchar(2),
c_address varchar(200),
primary key (c_id),
foreign key(c_id) references IDCard2 (I_id)
);
身份證表:id、身份證號
create table IDCard2(
I_id int auto_increment,
I_idno varchar(18) unique,
primary key (I_id)
);
Citizen2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Citizen2" table="citizen2" catalog="lai">
<id name="CId" type="java.lang.Integer">
<column name="c_id" />
<!-- 根據xxx的外鍵生成主鍵 -->
<generator class="foreign">
<param name="property">idcard2</param>
</generator>
</id>
<!-- 當前主鍵存在一個約束 constrained="true" -->
<!-- 將兩個類關聯起來 -->
<one-to-one name="idcard2" class="entity.Idcard2" constrained="true" >
</one-to-one>
<property name="CName" type="java.lang.String">
<column name="c_name" length="30" />
</property>
<property name="CAge" type="java.lang.Integer">
<column name="c_age" />
</property>
<property name="CGender" type="java.lang.String">
<column name="c_gender" length="2" />
</property>
<property name="CAddress" type="java.lang.String">
<column name="c_address" length="200" />
</property>
</class>
</hibernate-mapping>
IDCard2.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="entity.Idcard2" table="idcard2" catalog="lai">
<id name="IId" type="java.lang.Integer">
<column name="I_id" />
<generator class="increment"></generator>
</id>
<property name="IIdno" type="java.lang.String">
<column name="I_idno" length="18" unique="true" />
</property>
<!-- 關聯類 -->
<one-to-one name="citizen2" class="entity.Citizen2" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
Citizen2.java
private Integer CId;
private Idcard2 idcard2;
private String CName;
private Integer CAge;
private String CGender;
private String CAddress;
Idcard2.java
private Integer IId;
private String IIdno;
private Citizen2 citizen2;
運行的java代碼
Idcard2 id = new Idcard2("1111111321111");
Citizen2 ci = new Citizen2("mie", 18, "男", "日本");
id.setCitizen2(ci);
ci.setIdcard2(id);
session.save(id);
運行結果:
mysql> select * from IDCard2;
+------+----------------+
| I_id | I_idno |
+------+----------------+
| 2 | 1111111321111 |
| 1 | 11211111321111 |
+------+----------------+
2 rows in set (0.00 sec)
mysql> select * from Citizen2;
+------+--------+-------+----------+-----------+
| c_id | c_name | c_age | c_gender | c_address |
+------+--------+-------+----------+-----------+
| 1 | mie | 18 | 鐢? | 鏃ユ湰 |
| 2 | mie | 18 | 鐢? | 鏃ユ湰 |
+------+--------+-------+----------+-----------+
2 rows in set (0.00 sec)
-------------------------------------END主鍵映射END----------------------------------------
Hibernate數據加載
加載策略:lazy
類級別:<class ... lazy="true">(默認)true延遲加載||false立即加載
一對多關聯級別:<set ... lazy="true">(默認)true延遲加載||false立即加載||extra增強延遲加載
多對一關聯級別:<many-to-one ... lazy="proxy">(默認)proxy延遲加載||no-proxy無代理延遲加載||false立
即加載
多對多關聯級別:<many-to-many ... lazy="proxy" />(默認)proxy延遲加載||false立即加載
利用load方法加載對象,不會訪問表中的select語句,會生成一個對應表的代理類,代理類擁有一個屬性,主鍵。
Dept dept = (Dept)session.load(Dept.class,new Interger(10)); //此時的dept就屬於一個代理實例
在session關閉後,對應的代理實例就無法初始化
如果一對多中set標籤中採用的是立即加載,那麼,對一操作時,同時也會加載多,造成了性能的耗費
只有當dept初始化時,纔會訪問數據庫加載,調用其Set集合:
Set<Emp> emps = dept.getEmps();
Interator it = emps.interator()、size()、isEmpty()、contains();
Hibernate.initialize(emps); //初始化
當使用增強延遲加載的時候:他不會查詢所有的emp對象,他會比較聰明的發送聚合函數查詢數據的記錄數,起到
性能優化的作用
Dept dept = (Dept)session.load(Dept.class,new Interger(10));
Set<Emp> emps = dept.getEmps();
int Count = emps.size();
無代理延遲加載,是指只有遇到代理實例,纔開始訪問數據庫,加載程序
立即加載,逐行加載,賊耗性能
OpenSessionInView模式
在視圖層打開session:用戶每次請求過程中都保持一個Session對象打開
配置流程:
配置文件中加入
<!-- session綁定到當前線程OpenSessionIn View -->
<property name="hibernate.current_session_context_class">thread</property>
創建過濾器類
public class OpenSessionInViewFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
Transaction tx = null;
try {
Session session = HibernateSessionFactory.getSessionFactory
().getCurrentSession();
tx=session.beginTransaction();
chain.doFilter(request, response);
//返回響應時提交事務
tx.commit();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
tx.rollback();
}finally{
HibernateSessionFactory.closeSession();
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置上面的filter
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>tools.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
實際調用的時候:
//通過id返回該對象的代理類
public class DeptDaoImpl {
public Citizen2 getCitizen2(Integer id){
//這裏獲取的Session對象就是OpenSessionInViewFilter過濾器中打開的session,無需關閉session,
回到過濾器中會自己關閉
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession
();
//通過getCurrentSession創建的session會在事務提交後,或事物回滾,自動關閉
return (Citizen2) session .get(Citizen2.class, id);
}
}
Hibernate查詢
一、HQL:Hibernate Query Language 語法與SQL類似,但它是面向對象的,SQL是關係型數據
[select/delete/update...][from 實體類][where...][group by ...][having...][order by ...]
例:
String hql = "from Citizen2"; //編寫hql語句
Query query = session.createQuery(hql); //創建Query對象
List<Citizen2> idcard2 = query.list(); //得到封裝好的結果
System.out.println(idcard2.size()); //打印個數
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAge()); //打印輸出對應的屬性
}
解析:from Citizen2.其中select部分可以省略,from等關鍵詞可以大小寫隨意寫,但是Citizen2只能這麼些,這
表示一個類名.
不允許有大小寫的出入,完整的寫法,select e from Citizen2 as e,as可以省略,不能寫成select * from
Citizen2 e.其中e
表示對象名稱,表示查詢整個對象
/**執行時遇到了錯誤antlr.collections.AST.getLine()異常,原因是struts中的antlr2.x過時,和hibernate裏
的antlr2.7.6衝突**/
/**解決方法:刪除Myeclipse文件夾下/configuration/org.eclipse.osgi下刪除,再在/plugins/下搜索
*struts*,用壓縮包打開刪除掉,防止自動生成**/
帶條件查詢:
String hql = "from Citizen2 where CAge=?"; //條件語句,這裏查詢的是對象裏的參
數,不是數據庫裏的
//from Citizen2 e where e.CAge=?也行
Query query = session.createQuery(hql); //創建Query對象
query.setInteger(0, 18); //填充條件,第一個問號,jdbc從1開始
,hql從0開始
//setParameter可填充任意形式的字符,int,String
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCAddress());
}
模糊查詢(鏈式寫法):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString(0,"%運%"),setInteger(1,20).list();
也可以用名字佔位(先後順序可以打亂,參數前面加":"):
String hql = "from Citizen2 where CName like :name and CAge> :age ";
Query query = session.createQuery(hql);
List<Citizen2> cit = query.getString("name","%運%"),setInteger("age",20).list();
主鍵查詢(你確定只有一個結果值時):
String hql = "from Citizen2 where CName like ? and CAge>? ";
Query query = session.createQuery(hql);
Citizen2 cit = query.getString(0,"%運%"),setInteger(1,20).uniqueResult();
投影查詢(說的辣麼高級,其實就是一般的查詢列,最後用Object[]封裝而已,類似數組調用):
String hql = "select CId,CName from Citizen2";
Query query = session.createQuery(hql);
List<Object[]> idcard2 = query.list();
for (Object[] obj : idcard2) {
System.out.println(obj[0]+""+obj[1]);
}
返回的是部分值,和上面不同的是List<e>類型,弊端在於需要創建對應的構造函數(new ...)
String hql = "select new Citizen2(CId,CName) from Citizen2";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
排序(默認情況下,按照升序順序排序):下面是降序排序(order by e.CId desc)
String hql = "select e from Citizen2 e order by e.CId desc";
Query query = session.createQuery(hql);
List<Citizen2> idcard2 = query.list();
for (Citizen2 citizen2 : idcard2) {
System.out.println(citizen2.getCName()+" "+citizen2.getCId());
}
分頁(setFirstResult(n),setMaxResults(m))
String hql ="from Citizen2";
Query query = session.createQuery(hql);
//setFirstResult(0)設置第一條記錄的開始位置,這裏從0開始.setMaxResults(5):設置每頁
顯示的大小
query.setFirstResult(0).setMaxResults(5);//查詢結果1,2,3,4,5
List<Citizen2> cit = query.list();
for (Citizen2 citizen2 : cit) {
System.out.println(citizen2.getCId());
}
聚合函數(MYSQL中與HQL中對比)
mysql> select count(*) from Citizen2; String hql ="select count(e) from Citizen2 e";
+----------+ //這裏第一個e可以換成*或者其他參數,如CId···
| count(*) | Query query = session.createQuery(hql);
+----------+
| 10 | Long count = (Long)query.uniqueResult();
+----------+
1 row in set (0.00 sec) System.out.println(count);結果都是10
mysql> select min(c_id) from Citizen2; String hql ="select max(CId),min(CId),avg(CId)
from Citizen2 e";
+-----------+
| min(c_id) | Query query = session.createQuery(hql);
+-----------+
| 1 | Object[] count = (Object[])query.uniqueResult();
+-----------+
1 row in set (0.00 sec) for (int i = 0; i < count.length; i++) {
System.out.println(count[i]+"\t");
}
內鏈接:inner join||join
迫切內鏈接:inner join fetch||join fetch
左鏈接(迫切):left outer join (fetch)||left join (fetch)
右鏈接(迫切):right outer join (fetch) || right join
當然HQL還支持分組查詢、子查詢、表連接(拼接)等,不細細講了
Double d = 2.1111;//在製作商場網站時,需要製作Double調換,將Double轉換精度
new DecimalFormat("0.000").format(d);
二、QBC:Query By Criteria 是一組API提供了完全面向對象的接口、類、方法
專用於對SQL不太熟悉的開發者,主要使用到了Criteria對象,使用add()方法加入查詢條件,使用list()方法執行
查詢語句.設置條件,
用的比較多的是Restrictions類,而不是Expression類
例子:查詢該表
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:排序(傳入的一樣是類中字段,不是表中字段)
Criteria crit = session.createCriteria(Citizen2.class);
crit.addOrder(Order.desc("CId"));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:分頁查詢(和HQL的分頁類似,使用了setFirstResult()、setMaxResults()方法)
Criteria crit = session.createCriteria(Citizen2.class);
crit.setFirstResult(0).setMaxResults(3);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
例子:條件查詢(年齡等於22的)
Criteria crit = session.createCriteria(Citizen2.class);
crit.add(Restrictions.eq("CAge", 22));
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCName());
}
Restrictions查詢常用方法:
Restrictions.eq() 對應SQL的等於
Restrictions.allEq() 使用Map,對應多個相等的值對比
Restrictions.gt() 對應的SQL大於
Restrictions.ge() 對應的SQL大於等於
Restrictions.lt() 對應的SQL小於
Restrictions.le() 對應的小於等於
Restrictions.between() 對應的between子句
Restrictions.like() 對應的SQL的like子句
Restrictions.in() 對應的SQL的in子句
Restrictions.and() 對應的SQL的and子句
Restrictions.or() 對應的SQL的or子句
Restrictions.not() 對應的SQL的not子句
Restrictions.disjunction() 針對三個及三個以上的or或and條件查詢(如下:)
Criteria crit = session.createCriteria(Citizen2.class).add(Restrictions.disjunction().add
(Restrictions.gt("",""))
.add(Restrictions.ge("","")).add(Restrictions.eq("","")));
Restrictions.conjunction() 針對三個或者三個以上的and操作,將上述改成這個方法即可
Example查詢(主要用於查詢條件較多的時候,會把查詢條件封裝成一個類):
例子:
Citizen2 cit = new Citizen2();
cit.setCAge(22);
cit.setCName("樂運來");
cit.setCAddress("武漢市");
Criteria crit = session.createCriteria(Citizen2.class);
List<Citizen2> list = crit.add(Example.create(cit)).list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCId()+citizen2.getCAddress());
}
//List<Citizen2> list = crit.add(Example.create(cit).excludeProperty
("CName")).list();
還可以後面追加方法,將一些情況排除(上述添加的是excludeProperty("xxx"))
excludeZeroes(); 排除值爲0的屬性
excludePreperty("xxx") 排除xxx的屬性的條件
ignoreCase() 忽略大小寫比較
enableLike() 使用模糊查詢
如果要查詢所屬部門是SALES的員工有哪些,因爲部門名字是在dept表中,而結果是在emp表的內容,所以需要使用
到表連接查詢:
Criteria crit = session.createCriteria(Emp.class).createCriteria("dept").add(Restrictions.eq
("d_name","SALES"));
第二次可以理解爲表連接,查詢的是Emp數據,條件是dept裏的d_name等於SALES
同理也可以使用主鍵和外鍵查詢:session.createCriteria(Emp.class).add(Restrictions.eq
("dept.d_id",10));
Projections類的聚合函數
avg() 平均值
count() 出現的次數
countDistinct() 不重複值的數量
max() 最大值
min() 最小值
sum() 總和
例子:計算出現次數
Criteria crit = session.createCriteria(Citizen2.class);
crit.setProjection(Projections.count("CAge"));
Integer count = (Integer) crit.uniqueResult();
System.out.println(count);
例子:當計算的比較多的時候,利用ProjectionList裝進去
Criteria crit = session.createCriteria(Citizen2.class);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.max("CAge"));
projList.add(Projections.min("CAge"));
crit.setProjection(projList);
Object[] count = (Object[]) crit.uniqueResult();
System.out.println(count[0]+""+count[1]);
DetachedCriteria的使用(分離的Criteria,可用於不同條件下的查詢,複用性高)
//創建DetachedCriteria查詢規則,通過forClass方法創建
DetachedCriteria dc = DetachedCriteria.forClass(Citizen2.class);
//添加條件
dc.add(Restrictions.between("CAge", 18, 20));
dc.add(Restrictions.ilike("CName", "%i%"));
//開啓第一個會話
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
//通過DetachedCriteria得到Criteria對象,參與活動的是session
Criteria crit = dc.getExecutableCriteria(session);
List<Citizen2> list = crit.list();
for (Citizen2 citizen2 : list) {
System.out.println(citizen2.getCAge()+citizen2.getCId
()+citizen2.getCAddress());
}
tx.commit();
//關閉第一個會話
HibernateSessionFactory.closeSession();
//重新打開一個會話
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 = session2.beginTransaction();
//檢測是否是同一個會話,false表示不是一個
System.out.println(session==session2);
//通過DetachedCriteria得到Criteria對象,參與活動的是session
Criteria cri2 = dc.getExecutableCriteria(session2);
cri2.setProjection(Projections.sum("CAge"));
//再次得到查詢
Integer ob = (Integer)cri2.uniqueResult();
System.out.println(ob);
//關閉第二個會話
tx2.commit();
HibernateSessionFactory.closeSession();
當然,還可以用於子查詢
DetachedCriteria avg = DetachedCriteria.forClass(Emp.class).setProjection
(Property.forName("sal").avg());
//查詢工資高於平均工資的員工
List<Emp> emps = session.createCriteria(Emp.class).add(Property.forName('sal').gt
(avg)).list();
三、SQL:Structured Query Language 這是Hibernate提供的原生的SQL查詢方式,支持使用SQL語句的
方式查詢數據庫
//查詢表的全部參數,利用addEntity(Citizen2.class)方法轉換爲實體對象
Query q = session.createSQLQuery("select * from citizen2").addEntity
(Citizen2.class);
//.addScalar("c_id",Integer);用於查詢結果和標量值
List<Citizen2> n = q.list();
for (Citizen2 citizen2 : n) {
System.out.println(citizen2.getCName());
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.