一、导入相关依赖
方法一:通过maven,直接在pom.xml中写需要的版本
方法二:前往官网自己下载所需要的组件包
- documentation:存放镶滚文件与API
- lib:依赖,required子目录下为必须jar包
- project:源码资源与用例
将required下的jar包放入lib中,(非JavaWeb,则直接放在src下面即可)
别忘记build inpath以及JDBC也要导入。
二、创建配置文件
两种xml
在hibernate主要以两类xml为主:
- hibernate.cfg.xml:核心配置文件,用于连接数据库。本文以MySQL为例。
- 类名.hbm.xml:用于映射持久化类。即,记录了数据库的表,对应存储的类。自动将表的属性存放于类对应的成员变量之中。
本文的hibernate放在了resource下:
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--数据库基本参数-->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1/数据库名称</property>
<!--驱动名-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!--用户名、密码-->
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">mysql</property>
<!--hibernate方言路径,及hibernate的语法糖-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--可选设置-是否打印sql语句,即是否需要展现执行所对应的sql语句-->
<property name="hibernate.show_sql">true</property>
<!--可选设置-是否格式化sql语句,即sql语句是否以方便阅读的方式展现-->
<property name="hibernate.format_sql">true</property>
<!--hibernate映射路径,即我们所写的映射文件-->
<mapping resource="路径:类名.hbm.xml“/>
</session-factory>
</hibernate-configuration>
类名.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--名称相同时可以不用写数据库对应的部分-->
<!--类与表的对应-->
<class name="路径:类名" table="表名">
<!--成员变量与键值的对应-->
<id name="成员变量名" column="键名">
<!--主键生成策略,“本地生成”-->
<generator class="native"/>
<!--外键
<generator class="foreign">
<param name="property">成员变量名(是一个成员类,它的主键即为外键)</param>
</generator>
-->
</id>
<!--name – 对应类的属性名称
type – 指定属性的类型,一般情况下可以不用指定,由hibernate自动匹配(可参考文档中的有关说明)
length – 指定长度
column – 指定属性所对应的数据库字段的名称,如果不指定,就是属性的名称-->
<property name="成员变量名" column="属性"/>
</class>
</hibernate-mapping>
映射的类也应该为JavaBean类,即每一个对象都有对应的get与set方法。
generator的策略
- "assigned":主键由外部程序负责生成,需要在save()方法前指定(hibernate中的写入数据库方法)。这种主键的生成方式不建议使用,在数据库表设计时就应该使用代理主键(surrogate key),不应使用自然主键(natural key具有业务含义),在没有指定标签时,默认就是assigned主键的生成方式在插入数据的时候主键由用户自己添加,hibernate也不管。
- "hilo":通过hi/lo算法实现的主键生成机制,³使用一个高/低位算法生成的long、short或int类型的标识符,给定一个表和字段作为高位值的来源,默认的表是hibernate_unique_key,默认的字段是next_hi。它将id的产生源分成两部分,DB+内存,然后按照算法结合在一起产生id值,可以在很少的连接次数内产生多条记录,提高效率。
- "seqhilo":与"hilo"相似。sequence和hilo的结合,hilo的高位由sequence产生,所以也需要底层数据库的支持通过hilo算法实现,但是主键历史保存在Sequence中,适用于支持 Sequence 的数据库,如 Oracle(比较少用)。
- "increment":主键按顺序递增。³这个是由Hibernate在内存中生成主键,每次增量为1,不依赖于底层的数据库,因此所有的数据库都可以使用,但问题也随之而来,由于是Hibernate生成的,所以只能有一个Hibernate应用进程访问数据库,否则就会产生主键冲突,不能在集群情况下使用插入数据的时候hibernate会给主键添加一个自增的主键,但是一个hibernate实例就维护一个计数器,所以在多个实例运行的时候不能使用这个方法 。
- "identity":采用数据库的主键生成机制。适用于MySQL、DB2、MS SQL Server,采用数据库生成的主键,用于为long、short、int类型生成唯一标识 。
- "sequence":采用数据库提供的sequence机制生成主键。DB2、Oracle均支持的序列,用于为long、short或int生成唯一标识 。
- "native":hibernate自己判断,会根据底层数据库的能力,从identity、sequence、hilo中选择一个,灵活性更强,但此时,如果选择sequence或者hilo,则所有的表的主键都会从和hibernate默认的sequence或者hilo表中取。并且,有的数据库对于默认情况主键生成测试的支持,效率并不是很高。对于 oracle 采用 Sequence 方式,对于MySQL 和 SQL Server 采用。identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成。
- "uuid.hex":由hibernate基于128位UUID算法生成16位进制数值。(使用了IP地址+JVM的启动时间(精确到1/4秒)+系统时间+一个计数器值(在JVM中唯一) ),hibernate会算出一个128位的唯一值插入。
- "uuid.string":与uuid.hex类似,只是生成的主键未进行编码
- "foreign":使用另一个相关联的对象标识符作为主键(外键)
三、创建实体类
数据库
那么现在创建一个User类,其中uid为主键
package JavaBean;
public class User {
private int uid;
private String uname;
private String uimage;
private String pwd;
public User() {
this.uid = -1;
this.uname = null;
this.uimage = null;
this.pwd = null;
}
public int getUid() {
return this.uid;
}
public String getUname() {
return this.uname;
}
public String getUimage() {
return this.uimage;
}
public String getPwd() {
return this.pwd;
}
public void setUid(int UID) {
this.uid = UID;
}
public void setUname(String UNAME) {
this.uname = UNAME;
}
public void setUimage(String UIMAGE) {
this.uimage = UIMAGE;
}
public void setPwd(String PWD) {
this.pwd = PWD;
}
}
四、三个对象
- 瞬时对象(Transient Objects):使用new 操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回收。
- 持久化对象(Persist Objects):持久实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久实例是在事务中进行操作的——它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行SQL的INSERT、UPDATE和DELETE语句把内存中的状态同步到数据库中。
- 离线对象(Detached Objects):Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受Hibernate管理。
五、创建实体类-关系映射文件
<?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="JavaBean.User">
<id name="uid" column="UID">
<generator class="native"/>
</id>
<property name="uname" column="UName"/>
<property name="pwd" column="Pwd"/>
<property name="uimage" column="UImage"/>
</class>
</hibernate-mapping>
六、调用hibernateAPI完成操作
一般异常捕捉格式。
try{
}
catch(HibernateException ex){
ex.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
//如果有事务的话,建议回滚 session.getTransaction().rollback();
}
finally{
}
增
package Util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import JavaBean.User;
public class test {
public static void main(String[] args) {
//读取配置文件
Configuration cfg = new Configuration().configure();
//创建session级别的工厂,用于批量制造实例(工厂模式)
//同时该类会限制连接个数,类似于连接池,会占用连接数
//SessionFactory由Configuration对象创建,所以每个Hibernate配置文件,实际上是对SessionFactory的配置
SessionFactory factory = cfg.buildSessionFactory();
//此处的session是hibernate的会话,不是JavaWeb的
//Session不是线程安全的,它代表与数据库之间的一次操作,它的概念介于Connection和Transaction之间。Session也称为持久化管理器,因为它是与持久化有关的操作接口。
Session session = factory.openSession();
//开始事务,从现在开始到事务提交,都为原子级
session.beginTransaction();
//创建User类
User user = new User();
user.setUname("管理员");
user.setPwd("admin");
//让user变为持久化数据
session.save(user);
//提交事务
session.getTransaction().commit();
//关闭session工厂
if(session.isOpen()){
session.close();
}
}
}
查
不需要提交事务
package Util;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import JavaBean.User;
public class test {
public static void main(String[] args) {
//读取配置文件
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
//语句,User是类名,不是表名
Query query = session.createQuery("from User");
//Query query = session.createQuery("from User where UID = 1");
List users = query.list();
for(Iterator iter = users.iterator();iter.hasNext();) {
User user = (User)iter.next();
System.out.print("UserName:"+user.getUname()+"\n");
}
//关闭session工厂
if(session.isOpen()){
session.close();
}
}
}
改
package Util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import JavaBean.User;
public class test {
public static void main(String[] args) {
//读取配置文件
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
session.beginTransaction();
//参数一持久化类/全类名,参数二主键,参数三锁选项
User user = (User)session.get(User.class,3);
user.setPwd("123");
//提交事务
session.getTransaction().commit();
//关闭session工厂
if(session.isOpen()){
session.close();
}
}
}
删
package Util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import JavaBean.User;
public class test {
public static void main(String[] args) {
//读取配置文件
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
session.beginTransaction();
User user = new User();
user.setUid(3);
//语句
session.delete(user);
//提交事务
session.getTransaction().commit();
//关闭session工厂
if(session.isOpen()){
session.close();
}
}
}
session.get与session.load
- get方法会在调用之后,立即会向数据库发出sql语句,返回持久化对象;
- load方法会在调用后,会返回一个代理对象,该代理对象只保存了实体对象的id。直到使用对象的非主键属性时才会发出sql语句。
- 查询数据库中不存在的数据时,get方法返回null,而load方法则是会抛出异常。
七、多对一与一对一与多对多
cascade级联问题:
- all-代表在所有的情况下都执行级联操作
- none-在所有情况下都不执行级联操作
- save-update-在保存和更新的时候执行级联操作
- delete-在删除的时候执行级联操作
该句用在了类名.hbm.xml之中,代表该表与name中的类column中的属性发生了关联。
<!--本表 to 另一张表-->
<many-to-one name="" column="" cascade="all"/>
在未添加级联的情况下:
Group group = new Group();
group.setName("jkjk");
User user = new User();
user.setName("管理员");
//因为group为瞬时对象,此处无法继续
user.setGroup(group);
session.save(user);
我们需要这样做
Group group = new Group();
group.setName("jkjk");
//执行save操作之后,group对象变成持久化对象的状态
session.save(group);
User user = new User();
user.setName("管理员");
user.setGroup(group);
session.save(user);
在添加了后,我们第一种写法就可以了
Group group = new Group();
group.setName("A");
User user = new User();
user.setName("管理员");
user.setGroup(group);
session.save(user);
一对一(one-to-one)
一张表的一条记录对应另一张表的唯一一条记录
主键关联映射
onstrained属性是在主键映射一对一关系的时候会用到,用在引用方。
当前类名.hbm.xml对于name为限制,即当前的外键是主键且仅在name的类中唯一存在。
<one-to-one name="" constrained="true"/>
有外键的类
public class Person {
private int id;
private IdCard idCard;
}
<!--映射文件-->
<class name="com.bjsxt.hibernate.Person">
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<one-to-one name="idCard" constrained="true"/>
</class>
被引用主键的类
public class IdCard {
private int id;
private Person person;
}
<class name="com.bjsxt.hibernate.IdCard">
<id name="id">
<generator class="native"/>
</id>
<one-to-one name="person" cascade="all"/>
</class>
唯一外键关联映射
两个类本身都有一个自己的主码。我们想让他们关联,因为他们的主码都可以作为对方的候选码。那么,我们就会想让他们变为一对一关系,但又不想改动现在的主码,那么就需要这样写。
public class Mankind {
private String id;
private String name;
private Nose nose;
}
<class name="com.bjsxt.hibernate.Mankind">
<id name="id">
<generator class="uuid"/>
</id>
<property name="name"/>
<!--unique属性,使得这端唯一-->
<many-to-one name="nose" unique="true" cascade="all"></many-to-one>
</class>
另一个类
public class Nose {
private String id;
private Mankind mankind;
}
<class name="com.bjsxt.hibernate.Nose">
<id name="id">
<generator class="uuid"/>
</id>
<!--property-ref指定了关联类的成员类的名字,这个属性将会和本类的主键相对应。如果没有指定,会使用对方关联类的主键来跟本类的主键比较,-->
<one-to-one name="mankind" property-ref="nose" cascade="all"></one-to-one>
</class>
一对多(one to many)
public class Classes {
private String id;
private String name;
private Set students;
}
<hibernate-mapping>
<class name="com.bjsxt.hibernate.Classes">
<id name="id">
<generator class="uuid"/>
</id>
<property name="name" lazy="false" inverse = "true"/>
<set name="students">
<key column="classesid" ></key>
<one-to-many class="com.bjsxt.hibernate.Student" />
</set>
</class>
</hibernate-mapping>
public class Student {
private String id;
private String name;
}
多对多(many to many)
<class name="com.test.hibernate.Student">
<id name="id" column="userId"><generator class="native"/></id>
<set name="trainClasses" lazy="true" cascade="save-update">
<key column="studentId"/>
<many-to-many class="com.test.hibernate.TrainClass" column="trainClassId"/>
</set>
</class>
<class name="com.test.hibernate.TrainClass" table="TBL_TRAIN_CLASS">
<id name="id" column="trainClassId">
<generator class="native"/>
</id>
</class>
八、其他
inverse – 标记由哪一方来维护关联关系(双向关联中会用到)
lazy -- 延迟加载(懒加载),一般用于集合的抓取策略,也就是说只在需要用到的情况下,再发出select语句,将其相关的对象查询出来。默认为true
标准化查询
Criteria criteria = session.createCriteria(User.class);
criteria.add(Expression.like("name","J%"));
List users = criteria.list();