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();
效果展示: