一:HIbernate概述
二:Hibernate入门
Hibernate是个JavaSE项目,也适合JavaEE项目(JavaWeb)
Hibernate包歌文件说明:
1>documentation:存放Hibernate的相关文档,包括参考文档和API文档;
2>lib:存放hibernate编译与运行所依赖的jar包,其中required子目录下包含了运行Hibernate项目所必需的jar包;
3>project:存放了hibernate各种相关的源代码;
Hibernate的执行流程:
Configuration-->SessionFactory-->Session-->Transaction-->(save,delete,update,get)-->完成
1>Configuration是创建Configuration类的实例,以读取并解析配置文件(如Hibernate.cfg.xml),一个Configuration实例代表hibernate所有的Java类到sql数据库映射的集合
2>创建SessionFactory,以读取并解析映射信息,将Configuration对象的所有配置信息拷贝到SessionFactory的缓存中
对实体类的补充:
实体类必须包含一些属性,对应数据表的字段;
<span style="font-size:18px;"> @Column(name="aaaaa")
private int age;
private int TYPe;</span>
例如这两个属性,age属性加了@Column这个属性,那数据表的字段名字就是这个指定的,如果不加这个注解,比如TYPe,那个数据表生成的字段名就是这个属性名字;
实体类还要加与之对应的getXXX和setXXX方法,还包括无参构造器,这里是想强调,如果添加有参构造器的时候,一定要把无参构造器也写出来;
映射文件的解析:
实体类:
<span style="font-size:18px;">package com.anlw.entity;
public class Users {
private Integer id;
private String loginName;
private String logPwd;
public Users(){}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLogPwd() {
return logPwd;
}
public void setLogPwd(String logPwd) {
this.logPwd = logPwd;
}
}
</span>
映射文件:
<span style="font-size:18px;"><?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="com.anlw.entity.Users" table="user" catalog="bookshop">
<id name="id" type="java.lang.Integer">
<column name="Id" />
<generator class="native" />
</id>
<property name="loginName" type="java.lang.String">
<column name="LoginName" length="50" />
</property>
<property name="loginPwd" type="java.lang.String">
<column name="LoginPwd" length="255" />
</property>
</class>
</hibernate-mapping></span>
解释:
这个文件中,每个class节点配置一个实体类的映射信息,<class>节点的name属性对应实体类的名字,是类全名,有包名,table属性对应数据库表的名字,catalog对应数据库的名字;
在<class>节点下,必须有一个<id>节点,用于定义实体的标识属性(对应数据库表的主键),<id>节点的name的name属性对应实体类的属性,type是该属性的java类型,例如这里的id为实体类Users中的属性,该属性类型为Integer,<column>用于指定对应数据库表的主键,<generator>节点用于指定主键的生成策略;
Hibernate提供的常用主键的生成器策略:
1>increment:对象标识符由Hibernate以递增方式生成,如果有多个应用实例向同一张表插入数据时,则会出现重复的主键,应当谨慎使用;
2>identity:对象标识符由底层数据库的自增主键生成机制产生,要求底层数据库支持自增字段类型;如mysql的auto_increament类型主键和sql server的identity类型主键,还适用于DB2,Sybase和Hypersonic SQL;
3>sequence:对象标识符由底层数据库的序列生成机制产生,要求底层数据库支持序列,如Oracle数据库的序列,还适用于DB2,PostgreSQL,SAP DB,McKoi等;
4>hilo:对象标识符由Hibernate按照高/低位算法生成,该算法从特定表的字段读取高位值,默认情况下选用hibernate_unique_key表的next_hi字段,高/低位算法生成的标识符仅在一个特定的数据库中是唯一的;
5>native:根据底层数据库对自动生成标识符的支持能力,选择identity,sequence或hilo,适合跨数据库平台的开发;
6>assigned:对象标识符由应用程序产生,如果不能指定<generator>节点,则默认使用该生成器策略;
大部分数据库,如MySQL,Oracle,DB2等,都提供了易用的主键生成机制(identity字段或sequence),因此可以在数据库提供的主键生成机制上,采用<generator class="native">的主键生成方式;
<class>节点下除了<id>子节点,还包括<prooerty>子节点,用于映射普通属性;
<property>节点与<id>节点类似,只是不能包括<generator>子节点,每个<property>节点指定一对属性和字段的对应关系;
session核心代码:
<span style="font-size:18px;">package com.anlw.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateSessionFactory {
// 指定Hibernate配置文件路径
private static String CONFIG_FILE_LOCALTION = "/hibernate.cfg.xml";
// 创建ThreadLocal对象
private static final ThreadLocal<Session> sessionThreadLocal = new ThreadLocal<Session>();
// 创建Configuration对象
private static Configuration configuration = new Configuration();
// 定义SessionFactory对象
private static SessionFactory sessionFactory;
// 定义configFile属性并赋值
private static String configFile = CONFIG_FILE_LOCALTION;
static {
try {
// 读取配置文件hibernate.cfg.xml
configuration.configure();
// 生成一个注册机对象
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 使用注册机对象serviceRegistry创建sessuinFactory
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (HibernateException e) {
}
}
// 创建无参的HibernateSessionFactory构造器
private HibernateSessionFactory() {
}
// 获得SessionFactory对象
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// 重建SessionFactory
public static void rebuildSessionFactory() {
synchronized (sessionFactory) {
try {
configuration.configure(configFile);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
// 使用注册机对象serviceRegistry创建sessuinFactory
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (HibernateException e) {
}
}
}
// 获得Session对象
public static Session getSession() {
// 获得ThreadLocal对象管理的Session对象
Session session = (Session) sessionThreadLocal.get();
try {
// 判断Session对象是否存在或者已经打开
if (session == null || !session.isOpen()) {
// 如果Session对象为空或者未打开,再判断sessionFactory对象是否为空
if (sessionFactory == null) {
// 如果sessionFactory为空,则创建SessionFactory
rebuildSessionFactory();
}
// 如果sessionFRactory不为空,则打开Session
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
sessionThreadLocal.set(session);
}
} catch (HibernateException e) {
}
return session;
}
//关闭Session对象
public static void closeSession(){
Session session = sessionThreadLocal.get();
sessionThreadLocal.set(null);
try{
if(session != null && session.isOpen()){
session.close();
}
}catch(HibernateException e){}
}
//configFile属性的set方法
public static void setConfigFile(String configFile){
HibernateSessionFactory.configFile = configFile;
sessionFactory = null;
}
//configuration属性的get方法
public static Configuration getConfiguration(){
return configuration;
}
}
</span>
这个类中,首先通过一个静态代码块来启动,该代码只在类被加载时执行一次,用于创建SessionFactory,即这个SessionFactory是线程安全的,只能被实例化一次,save()方法和saveOrUpdate()方法的区别:
如果使用save,一个对象如果已经被持久化了,此时如果再次调用save方法,会出现异常,此时使用saveOrUpdate就可以解决这个问题,因为它会自动判断该对象是否已经持久化,如果已经持久化,将执行更新操作,否则执行添加操作,如果标识(主键)的生成策略是自增型的,则使用Session对象的save和saveOrUpdate方法是完全相同的;
session的save,saveOrUpdate方法(crud)除了查询,都必须是在事务环境中完成的,并需要commit方法提交事务,记录才能成功添加到数据表中;如果不提交commit事务,则这一次的id会被占用,但是写不到数据库;
Hibernate对象的三种状态:
1>瞬时态(Transient)(VO,Value Object)
2>持久态(Persistent)(PO,Persisence Object)
3>托管态(Detached)(VO,Value Object)
由new关键字创建的对象,如果他与数据库中的数据没有任何关联,也没有通过Session实例进行任何持久化操作,则该对象处于瞬时态,瞬时对象一旦不再被其他对象引用,那么很快被java虚拟机回收;
通过save和saveOrUpdate方法,可以将瞬时对象转变为持久对象,同时将对象中携带的数据插入到数据库的表中,处于持久态的对象在数据库中具有相应的记录,并拥有一个持久化标识,持久态对象位于一个session实例的缓存中,即总是与一个session实例相关联,当session清理缓存时,会根据持久对象的属性的变化同步更新到数据库;
持久对象的相关联的session实例执行delete方法后,持久态对象转变为瞬时态,同时删除数据库中相对应的记录,该对象不再与数据库的记录相关联;
当持久态对象相关联的的session实例执行close方法,clear或者evict方法后,持久对象转变为托管对象,此后,如果这个对象中的属性值发生变化,不会再将变化同步到数据库中;
托管状态对象如果不在被任何对象引用,将很快被垃圾回收,如果重新关联到session上时,托管状态再次转变为持久态,托管对象具有数据库记录标识,可以用seassion的update或者saveOrUpdate方法将托管状态转变为持久态,即对象与数据库记录同步
托管对象与瞬时对象的相同之处:如果不再被任何对象引用,将很快被垃圾回收;
托管对象与瞬时对象的不同之处:托管对象有数据库记录标识,瞬时态没有;
瞬时态或托管态转变为持久态的方法:
sava:瞬时态到持久态;.
load,get:获得对象的状态处于持久态;
find:获得的list集合中的对象处于持久态;(这个方法没找到,没有测试)
update,saveOrUpdate,lock方法可以将托管状态转变为持久态;(API提示lock这个方法已经过时)
持久态转变为托管状态的方法:
close:调用后,session的缓存会被清空,缓存中所有的持久态对象状态都转变为托管状态,处于托管状态的对象称为游离对象,当其不在被引用时,会虚拟机回收;
evict:可将session缓存中的一个指定的持久态对象删除,使其转变为托管状态,当缓存中存放大量处于持久态的对象时,为了节省内存空间,可以调用evict方法删除一些持久态对象;