Hibernate数据持久化详解

导读:本篇文章讲解 Hibernate数据持久化详解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

第一步:生成核心配置文件hibernate.cfg.xml加载数据库的配置信息

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

	<session-factory>
		<property name="myeclipse.connection.profile">Mysql</property>
		<property name="dialect">
			org.hibernate.dialect.MySQLDialect
		</property>
		<property name="connection.password">root</property>
		<property name="connection.username">root</property>
		<property name="connection.url">
			jdbc:mysql://127.0.0.1:3306/mydb
		</property>
		<property name="connection.driver_class">
			com.mysql.jdbc.Driver
		</property>
		<property name="show_sql">true</property><!-- 是否打印sql语句 -->
		<property name="format_sql">true</property>
		<mapping resource="com/cszy/model/Student.hbm.xml" />
	</session-factory>

</hibernate-configuration>

从配置文件我们可以看出,整个信息包括数据库的驱动,url地址,用户名,密码和hibernate方言等。

配置中的<property>元素常见配置属性如下
属性 说明
connection.driver_class 连接数据库驱动
connection.url 连接数据库的URL地址
connection.username 连接数据库用户名
connection.password 连接数据库密码
dialect 设置连接数据库使用的方言
show_sql 是否打印sql语句到控制台(默认为false,开发过程中建议设置为true)
format_sql 是否格式化sql语句,方便阅读

 

第二步:了解并编写持久化类(JOPO)

在Hibernate中,持久化类是hibernate操作的对象,也就是通过对象-关系映射(ORM)所映射的实体类。注:在持久化类中的属性应该与数据库表中的字段相匹配

创建名为Student的学生类

package com.cszy.model;

/**
 * Student entity. @author MyEclipse Persistence Tools
 */

public class Student implements java.io.Serializable {

	// Fields

	private Integer sno;	//id号
	private String sname;	//学生姓名
	private Integer sdept;	//学生所属班级

	// Constructors

	/** default constructor */
	public Student() {
	}

	/** full constructor */
	public Student(String sname, Integer sdept) {
		this.sname = sname;
		this.sdept = sdept;
	}

	// Property accessors

	public Integer getSno() {
		return this.sno;
	}

	public void setSno(Integer sno) {
		this.sno = sno;
	}

	public String getSname() {
		return this.sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public Integer getSdept() {
		return this.sdept;
	}

	public void setSdept(Integer sdept) {
		this.sdept = sdept;
	}

}

Student类作为一个持久类,要符合基本的JavaBean编码规范,也就是POJO编程模型。

生成Student的映射配置文件,其命名规范为*.hbm.xml,以Student的持久化的映射文件为例,如下

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
 <!-- name为持久化实体类的全名  table为数据库中表的名字 -->
    <class name="com.cszy.model.Student" table="student" catalog="hibernate">
        <!-- 下面为类中属性和表中的列一一对应 -->
        <id name="sno" type="java.lang.Integer">
            <column name="sno" />
            <generator class="native" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="sname" length="10" not-null="true" />
        </property>
        <property name="sdept" type="java.lang.Integer">
            <column name="sdept" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

<hibernate-mapping>元素是映射文件中其他元素的根元素,”package”属性指定一个包前缀,如果在<class>元素中没有指定全限定的类名,就将使用”package”属性定义的包前缀作为包名

<class>元素主要用于指定持久化类和映射数据库表名,”name”属性指定持久化类的全类名(com.cszy.model.Student);”table”属性指定数据表名字

<class>元素下一般包含一个id和多个property元素,id元素用于设置持久化类的唯一表示与数据库表的主键字段映射,在id元素中通过<generator>元素定义主键生成策略,一般设置为native,<property>元素用于持久化类的其他属性与数据库表其他非主键字段的映射。

持久化类映射文件中的<property>元素常见配置属性如下
属性 说明
name 持久化类属性名称,以小写字母开头
colum 数据库字段名
type 数据库字段第类型
length 数据库字段定义的长度
not-null 是否可以为空,boolean变量
unique 字段是否唯一,boolean变量
lazy 是否延迟抓取,boolean变量

 

注意:如果在映射文件中没有配置colum和type属性,那么hibernate将会默认使用持久化类中的属性名称和属性类型匹配数据库表中的字段

第三步:hibernate数据持久化

我们要使用 Hibernate 的功能,首先需要读取 Hibernate 的配置文件,根据配置启动 Hibernate ,然后创建 SessionFactory。

Hibernate初始化类

Session对象是Hibernate中数据库持久化操作的核心,他负责Hibernate所有的持久化操作。那么如何获取Session对象呢?

Session对象是通过SessionFactory对象获取的,而SessionFactory又是通过Configuration对象来创建的。(代码如下)

hibernate5和hibernate4等版本有所不同。

创建HibernateUtil类,实现对Hibernate的初始化

package com.cszy.hibernate;
 
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
 
public class HibernateUtil {
	//为保证线程安全,将Seeeion放到ThreadLocal中管理。这样就避免了Session的多线程共享数据的问题
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private static SessionFactory sessionFactory = null;//SessionFactory对象
    //静态块(在类被加载时执行,且生命周期内只执行一次)
	static {
    	try {
    		// 加载Hibernate配置文件
			Configuration cfg = new Configuration().configure();
			//	创建会话工厂
			//	hibernate4.0版本前这样获取sessionFactory = configuration.buildSessionFactory();
			//	hibernate5以后规定,所有的配置或服务,要生效,必须配置或服务注册到一个服务注册类(服务构建器-->服务注册器)
			ServiceRegistry serviceRegistry = cfg.getStandardServiceRegistryBuilder().build();
			//  根据服务注册类创建一个元数据资源集,同时构建元数据并生成应用一般唯一的的session工厂
			sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
		} catch (Exception e) {
			System.err.println("创建会话工厂失败");
			e.printStackTrace();
		}
    }
	/**
     *	获取Session
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();	//获取ThreadLocal中当前线程共享变量的值。
		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {		//如果会话工厂创建失败为空就在重新创建一次
				rebuildSessionFactory();
			}
			//创建Sqlsession数据库会话
			session = (sessionFactory != null) ? sessionFactory.openSession(): null;
			//设置ThreadLocal中当前线程共享变量的值。
			threadLocal.set(session);
		}
 
        return session;
    }
	/**
     * 重建会话工厂
     */
	public static void rebuildSessionFactory() {
    	try {
    		// 加载Hibernate配置文件
			Configuration cfg = new Configuration().configure();
			//	创建会话工厂
			//	hibernate4.0版本前这样获取sessionFactory = configuration.buildSessionFactory();
			//	hibernate5以后规定,所有的配置或服务,要生效,必须配置或服务注册到一个服务注册类(服务构建器-->服务注册器)
			ServiceRegistry serviceRegistry = cfg.getStandardServiceRegistryBuilder().build();
			//  根据服务注册类创建一个元数据资源集,同时构建元数据并生成应用一般唯一的的session工厂
			sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
		} catch (Exception e) {
			System.err.println("创建会话工厂失败");
			e.printStackTrace();
		}
	}
	/**
	 * 获取SessionFactory对象
	 * @return SessionFactory对象
	 */
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	/** 
     *	关闭Session
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        //使用set(null)来回收ThreadLocal设置的值.
        threadLocal.set(null);
        if (session != null) {
            session.close();//关闭Session
        }
    }
}

上面的类中有用到ThredLocal

简单理解可以认为:ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。

1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。

2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。

3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

ThreadLocal的set(null)和remove方法有什么区别?

set(null)把当前的ThreadLocal为key的值设为了空,避免线程下次再执行其他任务时被使用,但此时这个key对应的Entry值还在,只是Entry.value=null

remove方法会把这个key对应Entry的值设为空

 所以从重用和效率的角度来说,set(null)的性能优于remove,在实际的项目中推荐使用set(null)来回收ThreadLocal设置的值.

第四步:例如保存数据

hibernate的三种状态:

  • Transient State : 瞬时状态;
  • Persistent State : 持久状态;
  • Detached State : 离线状态或托管状态;

  • Transient State : 瞬时状态: 
    当我们new操作符初始化一个对象时,它处于瞬时态,也就是他没有任何和数据库表相关的行为,只要应用程序不再引用这些对象,它们状态将会丢失,被jvm垃圾回收了。总结,这个对象,Session没管理,数据库中没存。
  • Persistent State : 持久状态 : 
    持久化实例则是具有数据库标识的实例,它由持久化管理器Session统一管理的,只要它的状态发生改变,在事务提交时,会同步到数据库中。
  • Detached State : 离线状态或托管状态 : 数据库中有,但是session不管理了

创建addStudent.java,在main方法中关键代码如下:

package com.cszy.hibernate;

import org.hibernate.Session;

import com.cszy.model.Student;

public class AddStudent {
	public static void main(String[] args) {
		Session session = null;		//声明session对象
		Student student = new Student();	//实例化持久类
		student.setSname("二白");
		student.setSdept(1618);
		
		//Hibernate持久化操作
		try{
			session = HibernateUtil.getSession();	//获取Session
			session.beginTransaction();				//开启事务
			session.save(student);					//save执行数据库添加操作
			session.getTransaction().commit();      //事务提交
		}catch (Exception e) {
			session.getTransaction().rollback();    //事务回滚
			System.out.println("数据添加失败");
			e.printStackTrace();
		}finally {
			HibernateUtil.closeSession();           //关闭Session对象
		}
	}
}

读者可以根据该案例分析持久化对象student的实例状态改变流程,这将利于理解hibernate的数据持久化过程

说明:持久化对象student在创建之后是顺时状态(Transient),在Session执行save()方法之后,持久化对象student的状态变成持久化状态,但是这个时候数据库操作并未提交给数据库,在事务执行commit()方法之后,才完成数据库添加操作,此时的持久化对象student成为脏(dirty)对象。Session关闭之后持久化对象Student的状态变为脱管状态(Detached),并最后被JVM回收。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15243.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!