Hibernate细节

Hibernate细节

Hibernate核心类与接口

Hibernate细节_第1张图片

PSHibernate核心类与接口就是Hibernate框架的核心部分,通过对最底层配置文件的配置,将数据库与Java POJO进行映射,通过Configuration对象加载配置文件,再通过SessionFactory创建Session,得到会话之后就能进行CUD操作,然后可以使用CriteriaQuery进行R操作。当然在CRUD操作,请不要忘了Transaction这个事务控制接口。


1Configuration

Configuration类的作用如下:

    1负责管理hibernate的配置信息

    2读取hibernate.cfg.xml

    3加载hibernate.cfg.xml配置文件中配置的驱动,url,用户名,密码,连接池

4管理 *.hbm.xml对象映射文件

基本语法:

Configuration configuration = new Configuration().configure();

PS:请注意configure()方法是个重载方法,常用的有不带参数的和带一个String参数的,不带参数的默认加载src目录下的hibernate.cfg.xml文件,带参数的可以自己指定加载文件位置。


2Hibernate.cfg.xml文件

Hibernate.cfg.xml文件的作用如下:

    1该文件主要用于指定各个参数,hibernate核心文件

2默认放在src目录下,也可以放在别的目录下

3指定连接数据库的驱动、用户名、密码、url、连接池

4指定对象关系映射文件的位置

5也可使用hibernate.properties文件来替代该文件.(推荐使用hibernate.cfg.xml)

hibernate.cfg.xml案例:

<?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>

        <!-- Database connection settings -->
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">2</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

        <!-- Enable Hibernate's current session context -->
        <property name="current_session_context_class">org.hibernate.context.ManagedSessionContext</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create</property>

        <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>
        <mapping resource="org/hibernate/tutorial/domain/Person.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

3、对象关系映射文件(*.hbm.xml)

对象关系映射文件的作用:

    1该文件主要作用是建立表和类的映射关系,是不可或缺的重要文件

    2一般放在其映射的类同一个目录下,但不是必须的

    3命名方式一般是类名.hbm.xml,但不是必须的

对象关系映射文件示意图

Hibernate细节_第2张图片


4SessionFactory(会话工厂接口)

会话工厂接口的作用:

    1、可以缓存SQL语句和数据(Session级缓存[一级缓存])

    2SessionFactory是一个重量级对象,所以最好是保证一个数据库对应于一个SessionFactory。示意图如下:

Hibernate细节_第3张图片

    3、获取Session,有openSession()getCurrentSession()两个方法。

1openSession()获取一个新的Session

2getCurrentSession()获取和当前线程绑定的Session,也就是说,在同一个线程中,获取的Session一定是同一个Session,这样的话有利于事务控制。如果使用getCurrentSession()的话,需要在hibernate.cfg.xml中进行配置。

3、如何选择使用openSession()还是getCurrentSession()

    3.1、如果需要在同一线程中,保证使用同一个Session,则使用getCurrentSession()

    3.2、如果需要使用不同的Session,则使用openSession()

4、通过getCurrentSession()获取的Session在事务提交后,会自动关闭,通过openSession()获得的session则必须手动关闭。

5、通过getCurrentSession()获取SessionCRUD都要进行事务处理,通过openSession(),查询操作可以不进行事务处理。

6、在 SessionFactory启动的时候,Hibernate 会根据配置创建相应的 CurrentSessionContext,在getCurrentSession()被调用的时候,实际被执行的方法是 CurrentSessionContext.currentSession()。在currentSession()执行时,如果当前Session为空,currentSession会调用SessionFactoryopenSession


基本语法:

Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();

补充:全局事务和本地事务

本地事务是针对一个数据库的事务,其所有操作都是在一个数据库上面进行的。

全局事务是指跨数据库的事务,可以是一台主机上面的不同数据库,也可以是不同主机上面的不同数据库。


补充:getCurrentSession()线程会话

Hibernate细节_第4张图片


补充:获取Session工具类

package com.pc.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;

/**
 * 
 * @author Switch
 * @function 生成会话
 * @description 获取当前会话或者是创建新会话
 *
 */
public final class HibernateUtil {
	// 会话工厂
	private static SessionFactory sessionFactory = null;
	// 线程局部变量模式
	private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
	// 单例化,构造方法私有
	private HibernateUtil(){}
	
	// 静态代码块创建会话工厂
	static {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}
	
	// 获取全新的Session
	public static Session getOpenSession(){
		return sessionFactory.openSession();
	}
	
	// 获取和线程关联的Session
	public static Session getCurrentSession(){
		// 判断是否得到
		Session session = threadLocal.get();
		if(session == null){
			session = sessionFactory.openSession();
			// 把Session对象设置到threadLocal,相当于该session和线程绑定
			threadLocal.set(session);
		}
		return session;
	}
}

PS:通过ThreadLocal类可以将变量的作用域扩展为线程级,也就是说在本线程使用的都是同一个变量。遗憾的是该类只支持本地Session


5Session接口

会话接口的作用:

    1Session一个实例代表与数据库的一次操作(一次操作可以是crud组合),相当于JDBC里面的Connection接口实例。

    2Session实例通过SessionFactory获取,用完需要关闭。

    3Session是线程不同步的(不安全的),因此要保证在同一线程中使用,可以使用getCurrentSessiong()

    4Session可以看做是持久化管理器,它是与持久化操作相关的接口

 

基本语法:

Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();	// 需要配置
// 或者是: Session session = sessionFactory.openSession();

PS:还可以写工具类来实现,具体参照SessionFactory接口内容。


重要方法

1、保存一个对象(记录)——sava方法
    // 添加员工
	public static void addEmployee() {
		// 1.创建Configuration对象,该对象用于读取hibernate.cfg.xml,并完成初始化
		// configure默认载入hibernate.cfg.xml文件,可以指定需要载入的xml
		Configuration configuration = new Configuration().configure();
		// 2.创建SessionFactory对象(这是一个会话工厂,是一个重量级的对象)
		SessionFactory sessionFactory = configuration.buildSessionFactory();
		// 3.创建Session(用于与数据库的对话,相当于JDBC中的Connection)
		Session session = sessionFactory.openSession();
		// 4.对Hibernate而言,要求程序员,在进行增加、删除、修改的时候使用事务提交,否则不生效
		Transaction transaction = session.beginTransaction();
		// 添加一个雇员
		Employee employee = new Employee();
		employee.setName("zs");
		employee.setEmail("[email protected]");
		employee.setHiredate(new Date());
		// 保存
		// --->insert into ...[被hibernate封装]
		session.save(employee);
		// 提交
		transaction.commit();
		session.close();
	}

2、删除一个对象(记录)——delete方法
	// 删除员工信息
	public static void deleteEmployee() {
		// 获取一个会话
		Session session = HibernateUtil.getCurrentSession();

		// 创建一个事务
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			// 1.获取该雇员
			Employee employee = (Employee) session.load(Employee.class, 3);
			// 2.删除该雇员
			session.delete(employee);
			// 提交
			transaction.commit();
		} catch (Exception e) {
			// TODO: handle exception
			if (transaction != null) {
				transaction.rollback();
			}
			throw new RuntimeException(e.getMessage());
		} finally {
			if (session != null && session.isOpen()) {
				session.close();
			}
		}
	}

3、查询一个对象(记录)——get/load方法
get()load()的区别

1get()方法直接返回实体类,如果查不到数据则返回nullload()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时,如果没有数据不存在,就会抛出个org.hibernate.ObjectNotFoundException异常

2、load先到缓存(session缓存/二级缓存)中去查,如果没有则返回一个代理对象(不马上到DB中去找),等后面使用这个代理对象操作的时候,才到DB中查询,这就是我们常说的load在默认情况下支持延迟加载(lazy。可通过在Xxx.hbm.xmlclass元素中将lazy属性设置为false来取消延迟加载。

3、 get先到缓存(session缓存/二级缓存)中去查,如果没有就到DB中去查(即马上发出sql)。

4如果确定DB中有这个对象就用load(),不确定就用get()(这样效率高)


Hibernate缓存原理示意图
Hibernate细节_第5张图片


案例
-- 测试是否抛出异常
try {
    Session session = sessionFactory.openSession();
    //不会抛出异常.如果用load当查询不到则抛出异常
    Employee e=(Employee) session.get(Employee.class, 51);
    System.out.println(e);
    } catch (Exception e) {
    e.printStackTrace();
    // TODO: handle exception
    }finally{
}
-- 测试是否立即执行
-- 默认懒加载则不会立即执行,直到使用时才会执行
Employee emp=(Employee) session.load(Employee.class, 19);

4、修改一个对象(记录)——update方法
	// 修改员工信息
	public static void updateEmployee() {
		// 获取一个会话
		Session session = HibernateUtil.getCurrentSession();

		// 创建事务对象
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			// 1.获取要修改的雇员
			// load是通过主键属性,获取该对象实例(表的记录)
			Employee employee = (Employee) session.load(Employee.class, 2);
			// 2.修改该雇员
			employee.setName("ls");
			// 提交
			transaction.commit();
		} catch (Exception e) {
			// TODO: handle exception
			if (transaction != null) {
				transaction.rollback();
			}
			throw new RuntimeException(e.getMessage());
		} finally {
			if (session != null && session.isOpen()) {
				session.close();
			}
		}
	}

补充:Hibernate各种保存方式的区别(save,persist,update,saveOrUpdate,merge,flush,lock)等 
一、预备知识: 

在所有之前,说明一下,对于hibernate,它的对象有三种状态,transientpersistentdetached 

下边是常见的翻译办法: 

transient:瞬态或者自由态 

persistent:持久化状态 

detached:脱管状态或者游离态 

 

脱管状态的实例可以通过调用save()persist()或者saveOrUpdate()方法进行持久化。 

持久化实例可以通过调用 delete()变成脱管状态。通过get()load()方法得到的实例都是持久化状态的。 

脱管状态的实例可以通过调用 update()saveOrUpdate()lock()或者replicate()进行持久化。 

游离或者自由状态下的实例可以通过调用merge()方法成为一个新的持久化实例。 

 

save()persist()将会引发SQLINSERTdelete()会引发SQLDELETE, 而update()merge()会引发SQLUPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQL的UPDATEsaveOrUpdate()或者replicate()会引发SQL的INSERT或者UPDATE 


二、save update区别 

把这一对放在第一位的原因是因为这一对是最常用的。 

save的作用是把一个新的对象保存 

update是把一个脱管状态的对象保存 

 

三、update saveOrUpdate区别 

这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了saveupdate 

引用hibernate reference中的一段话来解释他们的使用场合和区别 

通常下面的场景会使用update()saveOrUpdate(): 

程序在第一个session中加载对象 

该对象被传递到表现层 

对象发生了一些改动 

该对象被返回到业务逻辑层 

程序调用第二个sessionupdate()方法持久这些改动 

 

saveOrUpdate()做下面的事

如果对象已经在本session中持久化了,不做任何事 

如果另一个与本session关联的对象拥有相同的持久化标识(identifier),抛出一个异常 

如果对象没有持久化标识(identifier)属性,对其调用save() 

如果对象的持久标识(identifier)表明其是一个新实例化的对象,对其调用save() 

如果对象是附带版本信息的(通过<version><timestamp>) 并且版本属性的值表明其是一个新实例化的对象,save()它。 

否则update() 这个对象 

 

四、persistsave区别 

这个是最迷离的一对,表面上看起来使用哪个都行,在hibernate reference文档中也没有明确的区分他们

这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别) 

这里参考http://opensource.atlassian.com/projects/hibernate/browse/HHH-1682中的一个说明: 

1persist把一个瞬态的实例持久化,但是并"不保证"标识符被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时间。 

 

2persist"保证",当它在一个transaction外部被调用的时候并不触发一个SQLinsert,这个功能是很有用的,当我们通过继承Session/persistence context来封装一个长会话流程的时候,一个persist这样的函数是需要的。 

 

3save"不保证"2,它要返回标识符,所以它会立即执行SQLinsert,不管是不是在transaction内部还是外部

 

五、saveOrUpdateCopy,mergeupdate区别 

首先说明merge是用来代替saveOrUpdateCopy的,这个详细见这里 

http://www.blogjava.net/dreamstone/archive/2007/07/28/133053.html 

然后比较updatemerge 

update的作用上边说了,这里说一下merge的 

如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例 

如果session没有相应的持久实例,则尝试从数据库中加载,或创建新的持久化实例,最后返回该持久实例 

用户给出的这个对象没有被关联到session上,它依旧是脱管的 

重点是最后一句: 

当我们使用update的时候,执行完成后,我们提供的对象A的状态变成持久化状态 

但当我们使用merge的时候,执行完成,我们提供的对象A还是脱管状态,hibernate或者new了一个B,或者检索到一个持久对象B,并把我们提供的对象A的所有的值拷贝到这个B,执行完成后B是持久状态,而我们提供的A还是托管状态 

 

六、flushupdate区别 

这两个的区别好理解 

update操作的是在脱管状态的对象 

flush是操作的在持久状态的对象。 

默认情况下,一个持久状态的对象是不需要update的,只要你更改了对象的值,等待hibernate flush就自动保存到数据库了。hibernate flush发生再几种情况下: 

1,调用某些查询的时候 

2transaction commit的时候 

3,手动调用flush的时候 

 

七、lockupdate区别 

update是把一个已经更改过的脱管状态的对象变成持久状态 

lock是把一个没有更改过的脱管状态的对象变成持久状态 

对应更改一个记录的内容,两个的操作不同: 

update的操作步骤是: 

(1)更改脱管的对象->调用update 

lock的操作步骤是: 

(2)调用lock把对象从脱管状态变成持久状态-->更改持久状态的对象的内容-->等待flush或者手动flush

 

参考博客:http://blog.csdn.net/looyo/archive/2009/07/15/4350937.aspx

 

6Transaction接口

事务接口的作用:

    1Transaction对应于数据库中事务这个概念,其具体可以参考之前的博客Oracle事务处理

    2Hibernate要求显示调用事务(如果仅仅是查询而且是使用openSession()获得会话可以不调用事务)

 

基本语法:

-- 事务开始
Transaction transaction = session.beginTransaction();
-- 事务提交
transaction.commit();
-- 事务回滚(异常处理)
transaction.rollback();

7Query接口

    Query接口类型的对象可以对数据库操作,它可以使用HQL,QBC,QBE和原生SQL(native Sql)对数据库操作.官方推荐使用HQL语句。

 

案例:

    // Query接口测试
	public static void queryEmployee() {
		Session session = HibernateUtil.getCurrentSession();
		Transaction transaction = null;
		try {
			transaction = session.beginTransaction();
			// 获取Query引用[Employee指的是domain类名而不是表名]
			// where后面的条件可以是类的属性名,也可以是表的字段
			// 按照hibernate的规定,还是应该使用类的属性名
			Query query = session.createQuery("from Employee where id=1");
			// 通过list方法获取结果,这个list会自动将结果封装成对应的domain对象
			// 所以JDBC进行二次封装的工作就没有了
			List<Employee> list = query.list();
			for(Employee e : list){
				System.out.println(e.getName() + " " + e.getEmail());
			}
			transaction.commit();
		} catch (Exception e) {
			// TODO: handle exception
			if(transaction != null){
				transaction.rollback();
			}
			throw new RuntimeException(e.getMessage());
		}  finally {
			if (session != null && session.isOpen()) {
				session.close();
			}
		}
	}

8Criteria接口

    Criteria接口也可以用于面向对象方式的查询。

 

案例:

        Session session = HibernateUtil.getCurrentSession();
		Transaction ts = null;
		try {
			ts = session.beginTransaction();
			Criteria cri = session.createCriteria(Employee.class)
					.setMaxResults(2).addOrder(Order.desc("id"));
			List<Employee> list = cri.list();
			for (Employee e : list) {
				System.out.println(e.getAaaid());
			}
			ts.commit();
		} catch (Exception e) {
			if (ts != null) {
				ts.rollback();
			}
			throw new RuntimeException(e.getMessage());
		} finally {
			// 关闭session
			if (session != null && session.isOpen()) {
				session.close();
			}
		}

使用MyEclipse开发Hibernate

开发步骤:

1、建库建表

2、创建一个项目

3、使用myeclipse自带的db browser连接到数据库

Hibernate细节_第6张图片

Hibernate细节_第7张图片

new一个数据库连接

Hibernate细节_第8张图片

4、引入hibernate支持(框架)[这里会自动创建hibernate.cfg.xml]

Hibernate细节_第9张图片

5、使用hibernate反向工程创建POJO类和对象映射文件

Hibernate细节_第10张图片

Hibernate细节_第11张图片

6、对各配置文件作相应的修改

7、编写测试类



----------参考《韩顺平.hibernate从入门到精通》


你可能感兴趣的:(java,Hibernate,框架,核心类与接口,MyEclipse开发)