Hibernate主鍵ID生成方式
數據庫中表有主鍵、主鍵的唯一性決定了數據庫表中記錄唯一。緩存在Session中的數據即實例都有一個唯一的ID,ID映射了數據庫中主鍵。那麼ID如何產生呢?
1、assigned:主鍵由外部程序負責生成,無需Hibernate參與。即當增加一個實體時,由程序設定它的ID值(手工分配值)
<class name="bean.Customer" table="customers" catalog="support">
<id name="customerId" type="java.lang.String">
<column name="customerID" length="8" />
<generator class="assigned"></generator>
</id>
.......
</class>
2、identity:在DB2、SQL Server、MySQL等數據庫產品中表中主鍵列可以設定是自動增長列,則增加一條記錄時主鍵的值可以不賦值。用數據庫提供的主鍵生成機制。
(1) 表結構:
create table test1 ( tid int not null primary key auto_increment,
name char(40));
(2) 映射文件
<class name="bean.Test1" table="test1" catalog="support">
<id name="tid" type="java.lang.Integer">
<column name="tid" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="40" />
</property>
</class>
3、increment:主鍵按數值順序遞增。此方式的實現機制爲在當前應用實例中維持一個變量,以保存着當前的最大值,之後每次需要生成主鍵的時候將此值加1作爲主鍵。這種方式可能產生的問題是:如果當前有多個實例訪問同一個數據庫,那麼由於各個實例各自維護主鍵狀態,不同實例可能生成同樣的主鍵,從而造成主鍵重複異常。因此,如果同一數據庫有多個實例訪問,此方式必須避免使用。
4、sequence: 採用數據庫提供的sequence 機制生成主鍵。
如Oralce中的Sequence,在Oracle中創建序列:
create sequence hibernate_sequence;
當需要保存實例時,Hibernate自動查詢Oracle中序列"hibernate_sequence"的下一個值;該值作爲主鍵值。可以改變默認的序列名稱。
5、native:由Hibernate根據底層數據庫自行判斷採用identity、hilo、sequence其中一種作爲主鍵生成方式。
6、uuid.hex:由Hibernate爲ID列賦值,依據當前客戶端機器的IP、JVM啓動時間、當前時間、一個計數器生成串,以該串爲ID值。
Hibernate 查詢方式
1、Hibernate查詢HQL語句
限制查詢結果記錄數與起始記錄
Session session=HibernateSessionFactory.getSession();
Query query=session.createQuery("from Customer");
query.setFirstResult(10); //設置查詢記錄開始位置,索引從0開始。
query.setMaxResults(10);//設置查詢返回的最大記錄個數。
List list=query.list();
注意:條件查詢
Session session=HibernateSessionFactory.getSession();
Query query=session.createQuery("from Customer cus where cus.name='zhou'");
2、取表中部分列時
(1) 單一屬性查詢。還是返回一個集合,只不過集合中存儲的不是表的實例而是對象。
Session session = null;
session = HibernateSessionFactory.getSession();
List cnames = session.createQuery("select cname from Customer").list();
for (int i=0;i< cnames.size();i++) {
String name = (String)cnames.get(i);
System.out.println(name);
}
(2) 多個屬性的查詢,使用對象數組。
Session session = null;
session = HibernateSessionFactory.getSession();
//查詢多個屬性,其集合元素是對象數組
//數組元素的類型,跟實體類的屬性的類型相關
List students = session.createQuery("select sno, sname from Students").list();
for (int i=0;i< students.size();i++) {
Object[] obj = (Object[])students.get(i);
System.out.println(obj[0] + ", " + obj[1]);
}
(3) 多個屬性的查詢,使用List集合裝部分列
Session session = HibernateSessionFactory.getSession();
Query query = session.createQuery("select new list(cus.name,cus.phone) from Customer cus");
List list = query.list();
for (int i = 0; i < list.size(); i++) {
List temp=(List)list.get(i);
System.out.println(temp.get(0)); //0是索引
}
(4) 使用Map集合裝部分列
Session session = HibernateSessionFactory.getSession();
Query query = session.createQuery("select new map(cus.name,cus.phone) from Customer cus");
List list = query.list();
for (int i = 0; i < list.size(); i++) {
Map temp=(Map)list.get(i);
System.out.println(temp.get("1")); //"1"是key
}
3、內連接
Query query=session.createQuery("select c.name, s.name from Student s join s.classes c ").list();
for (Iterator iter = students.iterator();iter.hasNext();) {
Object[] obj = (Object[])iter.next();
System.out.println(obj[0] + ", " + obj[1]);
}
4、外連接
select c.name, s.name from Classes c left join c.students s
select c.name, s.name from Classes c right join c.students s
5、帶參數的查詢
(1) ?作爲參數 如" from Customer cus where cus.name=?";
Session session = HibernateSessionFactory.getSession();
Query query = session.createQuery("from Customer cus where cus.name=?");
query.setParameter(0, "zhou");
List list = query.list();
(2) 參數名稱 :name 如" from Customer cus where cus.name=:name";
Session session = HibernateSessionFactory.getSession();
Query query = session.createQuery("from Customer cus where cus.name=:name ");
query.setParameter("name", "zhou");
List list = query.list();
(3) 條件查詢,使用 ?的方式傳遞參數
Query query = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE ?");
query.setParameter(0, “%周%”); //傳遞參數參數的索引是從0開始的。 如條件查詢,使用":參數"名稱的方式傳遞參數
Query query = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE :myname");
query.setParameter("myname", "張三");//傳遞參數
因爲setParameter方法返回Query接口,所以可用省略方式來查詢
List students = session.createQuery("SELECT s.id, s.name FROM Student s WHERE s.name LIKE :myname and s.id = :myid")
setParameter("myname", "%周%").setParameter("myid", 15).list();
6、嵌入原生sql測試
SQLQuery sqlQuery = session.createSQLQuery("select * from t_student");
List students = sqlQuery.list();
for (Iterator iter = students.iterator();iter.hasNext();) {
Object[] obj = (Object[])iter.next();
System.out.println(obj[0] + ", " + obj[1]);
}
Hibernate多表操作
關係型數據庫具有三種常用關係:一對一關係、一對多關係和多對多關係。
建立了一對多關係的表之間,一方中的表叫“主表”,多方中的表叫“子表”;兩表中相關聯的字段,在主表中叫“主鍵”,在子表中稱“外鍵”。
級聯操作與延遲加載
1、cascade級聯操作
所謂cascade,如果有兩個表,在更新一方的時候,可以根據對象之間的關聯關係,對被關聯方進行相應的更新。
all :所有情況下均進行關聯操作。
none:所有情況下均不進行關聯操作。這是默認值。
save-update:執行save/update/saveOrUpdate時進行關聯操作
delete:在執行delete時進行關聯操作。
2、inverse屬性
3、延遲加載
(1) 屬性的延遲加載
如Person表有一個人員圖片字段(對應java.sql.Clob類型)屬於大數據對象,當我們加載該對象時,我們不得不每一次都要加載這個字段,而不論我們是否真的需要它,而且這種大數據對象的讀取本身會帶來很大的性能開銷。我們可以如下配置我們的實體類的映射文件:
<hibernate-mapping>
<class name="bean.Person" table="person">
……
<property name="pimage" type="java.sql.Clob"
column="pimage" lazy="true"/>
</class>
</hibernate-mapping>
代碼:
當寫完上一個單表操作時,發現再進行多表操作時,student的外鍵dept不能再用string,而應該是建一個對象。在多表級聯操作時,都應建一個對象
爲了減少冗餘,這裏只貼出關鍵代碼。
HibDemoServlet.java
package cn.hncu.servlet;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hncu.domain.Dept;
import cn.hncu.domain.Student;
import cn.hncu.service.HibDemoServiceImpl;
import cn.hncu.utils.BaseServlet;
public class HibDemoServlet extends BaseServlet {
private HibDemoServiceImpl service=new HibDemoServiceImpl();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp)
throws Exception {
List<Dept> list=service.queryAllDepts();
req.setAttribute("list",list);
String resultPage=getInitParameter("show");
req.getRequestDispatcher(resultPage).forward(req, resp);
}
public void queryDept(HttpServletRequest req, HttpServletResponse resp)
throws Exception {
String deptId=req.getParameter("deptId");
String deptName=req.getParameter("deptName");
Dept dept=new Dept();
dept.setDeptId(deptId);
dept.setDeptName(deptName);
List<Dept> depts=service.queryDept(dept);
req.getSession().setAttribute("depts", depts);
resp.sendRedirect(req.getContextPath()+"/jsps/qresult.jsp");
}
public void addDept(HttpServletRequest req, HttpServletResponse resp)
throws Exception {
//按理添加數據的時候應該從前臺獲取數據然後進行封裝,這裏省略了
Dept dept=new Dept();
dept.setDeptId("D004");
dept.setDeptName("外國語學院");
Student stud1=new Student();
stud1.setId("S008");
stud1.setName("S1");
stud1.setAge(18);
stud1.setDept(dept);//注:多方要添加一方
Student stud2=new Student();
stud2.setId("S009");
stud2.setName("S2");
stud2.setAge(19);
stud2.setDept(dept);
dept.getStudents().add(stud1);//一方添加多方
dept.getStudents().add(stud2);
try {
service.addDept(dept);
System.out.println("添加成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("添加失敗!");
}
}
}
show.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<style type="text/css">
table{
border: 1px solid blue;
border-collapse: collapse;
width:60%;
}
td,th{
border: 1px solid blue;
padding: 5px;
}
#t2 tr{
text-align: center;
}
iframe{
height: 50%;
width: 60%;
}
</style>
</head>
<body>
<h2>演示Hibernate進行表與表之間操作</h2>
<table>
<tr align="center">
<th>學院編號</th>
<th>學院名稱</th>
</tr>
<c:forEach items="${list}" var="dept">
<tr align="center">
<td>${dept.deptId }</td>
<td>${dept.deptName }</td>
</tr>
</c:forEach>
</table>
<br/><br/><br/>
<h3>學生詳細信息查詢</h3>
<form action="<c:url value='/HibDemoServlet?cmd=queryDept' />" method="post" target="f1">
<table id="t2">
<tr>
<td>學院編號</td><td><input type="text" name="deptId" /></td>
</tr>
<tr>
<td>學院名稱</td><td><input type="text" name="deptName" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="查詢"/></td>
</tr>
</table>
</form>
<iframe name="f1" ></iframe><br/><br/>
<a href="<c:url value='/HibDemoServlet?cmd=addDept' />">Hibernate中表與表之間的級聯操作</a>
<br/> <br/> <br/><br/><br/>
</body>
</html>
Student.java
package cn.hncu.domain;
/*
* 要在hibernate中實現表與表之間的關係(以一對多爲例)
*/
public class Student {
private String id;
private String name;
private Integer age;
//添加一個用於存儲一方的對象
private Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age
+ ", dept=" + dept + "]";
}
}
Dept.java
package cn.hncu.domain;
import java.util.HashSet;
import java.util.Set;
/*
* 要在hibernate中實現表與表之間的關係(以一對多爲例)
*/
public class Dept {
private String deptId;
private String deptName;
//添加一個用於存儲多方的集合
private Set<Student> students=new HashSet<Student>();//一定要提前new 出來,不然會出現空指針異常
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "Dept [deptId=" + deptId + ", deptName=" + deptName + "]";
}
}
Student.hib.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 package="cn.hncu.domain">
<class name="Student" table="students" catalog="hib">
<id name="id" column="id" type="java.lang.String"></id>
<property name="name" >
<column name="name"></column>
</property>
<property name="age">
<column name="age"></column>
</property>
<!-- 在hibernate中實現表與表之間關係(以一對多爲例) -->
<!-- 下面這一段是相比單表不同的地方,配置多對一的關係即值對象中的"dept"屬性 -->
<many-to-one name="dept" class="Dept" fetch="select">
<column name="deptId"></column>
</many-to-one>
</class>
<class name="Dept" catalog="hib" table="depts">
<id name="deptId" type="java.lang.String">
<column name="id" length="8"></column>
<generator class="assigned"></generator><!-- 主鍵由外部程序負責生成,無需Hibernate參與。即當增加一個實體時,由程序設定它的ID值(手工分配值) -->
</id>
<property name="deptName" column="name"></property>
<!-- 在hibernate中實現表與表之間關係(以一對多爲例) -->
<!-- 下面這一段是相比單表不同的地方,配置多對一的關係即值對象中的"students"集合屬性 -->
<set name="students" table="students" inverse="true" cascade="all">
<key>
<column name="deptId"></column>
</key>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>
HibDemoJdbc.java
package cn.hncu.dao;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.hncu.domain.Dept;
import cn.hncu.domain.Student;
import cn.hncu.hib.HibernateSessionFactory;
public class HibDemoJdbcDao {
public List<Dept> queryAllDepts(){
Session session=HibernateSessionFactory.getSession();
//SQL ---Structured Query Language ---面向R(關係--表)
//HQL ---Hibernate Query Language ---面向O(值對象)
Query query=session.createQuery("from Dept");//HQL
List<Dept> depts=query.list();
return depts;
}
//條件查詢
public List<Dept> queryDept(Dept dept) {
Session session=HibernateSessionFactory.getSession();
//清緩存
session.clear();
String hql="from Dept d where 1=1";
String deptId=dept.getDeptId();
String deptName=dept.getDeptName();
int flag=0;
//HQL語句中的類字段,是java類中的字段,不是數據庫中的字段;
if(deptId!=null&&deptId.trim().length()>0){
hql+="and d.deptId=?";
flag|=1;
}
if(deptName!=null&&deptName.trim().length()>0){
hql+="and d.deptName like ?";
flag|=2;
}
Query query=session.createQuery(hql);
if(flag==1||flag==3){
query.setParameter(0, deptId.trim());
}
if(flag==2){
query.setParameter(0, "%"+deptName+"%");//模糊查詢
}
if(flag==3){
query.setParameter(1, "%"+deptName.trim()+"%");
}
List<Dept> depts= query.list();
return depts;
}
public void addDept(Dept dept) {
Session session=HibernateSessionFactory.getSession();
Transaction tr=session.beginTransaction();
session.save(dept);//只能進行添加,若id存在則添加失敗
tr.commit();//必須進行事務提交才能保存到數據庫
}
}
qresult.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<style type="text/css">
table{
border: 1px solid blue;
border-collapse: collapse;
width:60%;
}
td,th{
border: 1px solid blue;
padding: 5px;
}
#t2 tr{
text-align: center;
}
</style>
</head>
<body>
<h2>學院基本信息</h2>
<c:forEach items="${depts}" var="dept">
編號:${dept.deptId} , 名稱:${dept.deptName}
<table>
<tr align="center">
<th>學號</th>
<th>姓名</th>
<th>年齡</th>
</tr>
<c:forEach items="${dept.students}" var="student">
<tr align="center">
<td>${student.id }</td>
<td>${student.name }</td>
<td>${student.age }</td>
</tr>
</c:forEach>
</table>
</c:forEach>
<br/><br/><br/>
</body>
</html>
//清hibernate緩存
session.clear();
效果展示: