Hibernate学习笔记(1)Hibernate构造

一 准备工做

首先,咱们将建立一个简单的基于控制台(console-based)Hibernate应用。html

咱们所作的第一件事就是建立咱们的开发文件夹。并把全部须要用到的Java件放进去。解压缩从Hibernate站点下载的Hibernate公布包。并把所有需要的库文件拷到咱们项目中去。
学习建User-library-hibernate,并增长对应的jar包

(a)项目右键-buildpath-configure build path-add libraryjava


(b)选择User-library,在当中新建 hibernate,命名为HibernateLibraray

(c)在该library中增长hibernate所需jar包mysql


到编写本文时为止。这些是Hibernate执行所需要的最小库文件集合(注意咱们也拷贝了 Hibernate3.jar,这个是最基本的文件)。
你正使用的Hibernate版本号可能需要比这不少其它或少一些的库文件。请參见公布包中的lib/文件夹下的README.txt,以获取不少其它关于所需和可选的第三方库文件信息(其实。Log4j并不是必须的库文件,但被不少开发人员所喜欢)。web

(d) 引入sqlserver的JDBC驱动包 sql

在sqlserver中建立表StudentInfo数据库



接下来咱们建立一个类。用来表明那些咱们但愿储存在数据库里的student。编程



二 持久化类

咱们的第一个持久化类是一个带有一些属性(property)的简单JavaBean类:安全

package com.model;

public class StudentInfo {
	private int id;
	private String name;
	private int age;
	private String sex;
	
	//构造方法
	public StudentInfo(){
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
}

你可以看到这个类对属性的存取方法(getter and setter method)使用了标准JavaBean命名约定。同一时候把类属性(field)的訪问级别设成私有的(private)。
这是推荐的设计,但并不是必须的。Hibernate也可以直接訪问这些field,而使用訪问方法(accessor method)的优势是提供了重构时的健壮性(robustness)。
为了经过反射机制(Reflection)来实例化这个类的对象。咱们需要提供一个无參的构造器(no-argument constructor)。

 
对一特定的StudentInfo, id 属性持有惟一的标识符(identifier)的值。假设咱们但愿使用Hibernate提供的所有特性,
那么所有的持久化实体(persistent entity)类(这里也包含一些次要依赖类)都需要一个这种标识符属性。
而其实,大多数应用程序(特别是web应用程序)都需要经过标识符来差异对象,因此你应该考虑使用标识符属性而不是把它看成一种限制。
然而,咱们一般不会操做对象的标识(identity),所以它的setter方法的訪问级别应该声明private。session

这样当对象被保存的时候,仅仅有Hibernate可以为它分配标识符值。
你可看到Hibernate可以直接訪问public,private和protected的訪问方法和field。app

因此选择哪一种方式全然取决于你。你可以使你的选择与你的应用程序设计相吻合。

 
所有的持久化类(persistent classes)都要求有无參的构造器。因为Hibernate必须使用Java反射机制来为你建立对象。


构造器(constructor)的訪问级别可以是private,然而当生成执行时代理(runtime proxy)的时候则要求使用至少是package 级别的訪问控制,
这样在没有字节码指令(bytecode instrumentation)的状况下。从持久化类里获取数据会更有效率。 

下一步,咱们把这个持久化类的信息告诉Hibernate。


三 映射文件

Hibernate需要知道如何去载入(load)和存储(store)持久化类的对象。这正是Hibernate映射文件发挥做用的地方。
映射文件告诉Hibernate它,应该訪问数据库(database)里面的哪一个表(table)及应该使用表里面的哪些字段(column)。 

一个映射文件的基本结构看起来像这样:

<?

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> [...] </hibernate-mapping>


注意Hibernate的DTD是很复杂的。

你的编辑器或者IDE里使用它来本身主动完毕那些用来映射的XML元素(element)和属性(attribute)。


你也可以在文本编辑器里打开DTD-这是最简单的方式来概览所有的元素和attribute,并查看它们的缺省值以及凝视。

注意Hibernate不会从web载入DTD文件,
但它会首先在应用程序的classpath中查找。DTD文件已包含在hibernate3.jar里,同一时候也在Hibernate公布包的src/文件夹下。

 
为缩短代码长度,在之后的样例里咱们会省略DTD的声明。固然。在实际的应用程序中,DTD声明是必须的。

 
在hibernate-mapping标签(tag)之间, 含有一个class元素。所有的持久化实体类(再次声明,也许接下来会有依赖类。就是那些次要的实体)都需要一个这种映射,来把类对象映射到SQL数据库里的表。

 

<hibernate-mapping>
    <class name="com.model.StudentInfo" table="StudentInfo">
    </class>
</hibernate-mapping>

到眼下为止,咱们告诉了Hibernate如何把StudentInfo类的对象持久化到数据库的StudentInfo表里。以及如何从StudentInfo表载入到StudentInfo类的对象。


每个实例相应着数据库表中的一行。现在咱们将继续讨论有关惟一标识符属性到数据库表的映射。另外。由于咱们不关心如何处理这个标识符。咱们就配置由Hibernate的标识符生成策略来产生代理主键字段。


<hibernate-mapping>
    <class name="com.model.StudentInfo" table="StudentInfo">
        <id name="id" column="ID">
            <generator class="native"/>
        </id>
    </class>
</hibernate-mapping>

id元素是标识符属性的声明,name="id" 声明了Java属性的名字 - Hibernate会使用getId()和setId()来訪问它。 
column属性则告诉Hibernate, 咱们使用StudentInfo表的哪一个字段做为主键。

嵌套的generator元素指定了标识符生成策略,在这里咱们指定native,
它依据已配置的数据库(方言)本身主动选择最佳的标识符生成策略。

Hibernate支持由数据库生成,全局惟一性(globally unique)和应用程序指定(或者你本身为不论什么已有策略所写的扩展)这些策略来生成标识符。 

最后咱们在映射文件中面包括需要持久化属性的声明。

默认状况下。类里面的属性都被视为非持久化的:

<hibernate-mapping>
    <class name="com.model.StudentInfo" table="StudentInfo">
        <id name="id" column="ID">
            <generator class="native"/>
        </id>
        <property name="date" type="timestamp" column="EnterDate"/>
        <property name="title"/>
    </class>
</hibernate-mapping>

id元素同样。property元素的name属性告诉Hibernate使用哪一个getter和setter方法。在此例中。Hibernate会寻找getDate()/setDate(), 以及getTitle()/setTitle()

为何date属性的映射含有column attribute,而title却没有?当没有设定column attribute 的时候。Hibernate缺省地使用JavaBean的属性名做为字段名。对于title,这样工做得很是好。然而。date在多数的数据库里。是一个保留keyword,因此咱们最好把它映射成一个不一样的名字。

还有一有趣的事情是title属性缺乏一个type attribute。

咱们在映射文件中声明并使用的类型。却不是咱们指望的那样。是Java数据类型。同一时候也不是SQL数据库的数据类型。这些类型就是所谓的Hibernate 映射类型(mapping types),它们能把Java数据类型转换到SQL数据类型。反之亦然。再次重申。假设在映射文件中没有设置type属性的话,Hibernate会本身试着去肯定正确的转换类型和它的映射类型。在某些状况下这个本身主动检測机制(在Java 类上使用反射机制)不会产生你所期待或需要的缺省值。date属性就是个很是好的样例,Hibernate没法知道这个属性(java.util.Date类型的)应该被映射成:SQLdate。或timestamp,仍是time 字段。

在此例中,把这个属性映射成timestamp 转换器。这样咱们预留了日期和时间的全部信息。

应该把这个映射文件保存为Event.hbm.xml,且就在StudentInfo Java类的源文件文件夹下。映射文件可任意地命名,但hbm.xml的后缀已成为Hibernate开发人员社区的约定。

对于StudentInfo的配置例如如下:

<?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="com.model.StudentInfo" table="StudentInfo">
		<id name="id" column="ID">
            <generator class="native"/>
        </id>
		<property name="name" column = "Name"/>
		<property name="age" column = "Age"/>
		<property name="sex" column = "Sex"/>
    </class>
</hibernate-mapping>

咱们继续进行Hibernate的主要配置。


四 Hibernate配置

现在咱们已经有了一个持久化类和它的映射文件,该是配置Hibernate的时候了。在此以前。咱们需要一个数据库。


Hibernate是你的应用程序里链接数据库的那层。因此它需要链接用的信息。链接(connection)是经过一个也由咱们配置的JDBC链接池(connection pool)来完毕的。


Hibernate的公布包里包括了不少开源的(open source)链接池。注意,假设你但愿使用一个产品级(production-quality)的第三方链接池软件,你必须拷贝所需的库文件到你的classpath下,并使用不一样的链接池设置。 
为了保存Hibernate的配置,咱们可以使用一个简单的hibernate.properties文件,或者一个略微复杂的hibernate.cfg.xml,甚至可以全然使用程序来配置Hibernate。多数用户更喜欢使用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 -->
        <!-- MySql配置 -->
        <!--<property name="connection.driver_class">com.mysql.jdbc.Driver</property> -->
        <!--<property name="connection.url">jdbc:mysql://localhost/hibernate</property> -->
        <!-- SQL dialect -->
        <!--<property name="dialect">org.hibernate.dialect.MySQLDialect</property>-->
        <!-- SqlServer配置 -->
        <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="connection.url">jdbc:sqlserver://localhost/Hibernate</property>
        <!-- 数据库用户名 -->
        <property name="connection.username">sa</property>
        <!-- 数据库密码 -->
        <property name="connection.password">123</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>
        
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.SQLServerDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</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="com/model/StudentInfo.hbm.xml"/>
    </session-factory>

</hibernate-configuration>

注意这个XML配置使用了一个不一样的DTD。在这里。咱们配置了Hibernate的SessionFactory-一个关联于特定数据库全局的工厂(factory)。
假设你要使用多个数据库,就要用多个的<session-factory>,一般把它们放在多个配置文件里(为了更easy启动)。 
最開始的4个property元素包括必要的JDBC链接信息。方言(dialect)的property元素指明Hibernate 生成的特定SQL变量。你很是快会看到,Hibernate对持久化上下文的本身主动session管理就会派上用场。
 打开hbm2ddl.auto选项将本身主动生成数据库模式(schema)- 直接增长数据库中。固然这个选项也可以被关闭(经过去除这个配置选项)或者经过Ant任务SchemaExport的帮助来把数据库schema重定向到文件里。


 最后,在配置中为持久化类增长映射文件。

 



Demo下载地址:点击打开连接


五启动和辅助类

是时候来载入和储存一些StudentInfo对象了,但首先咱们得编写一些基础的代码以完毕设置。
咱们必须启动Hibernate,此过程包含建立一个全局的SessoinFactory,并把它储存在应用程序代码easy訪问的地方。SessionFactory可以建立并打开新的Session。一个Session表明一个单线程的单元操做。SessionFactory则是个线程安全的全局对象,仅仅需要被实例化一次。 

咱们将建立一个HibernateUtil辅助类(helper class)来负责启动Hibernate和更方便地操做SessionFactory。让咱们来看一下它的实现:

package com.util;

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

public class HibernateUtil {
	
	private static final SessionFactory sessionFactory;
    static 
    {
        try 
        {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory = new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) 
        {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

这个类不但在它的静态初始化过程(仅当载入这个类的时候被JVM运行一次)中产生全局的SessionFactory,而且隐藏了它使用了静态singleton的事实。


它也可能在应用程序server中的JNDI查找SessionFactory。 

演示样例的基本框架完毕了 - 现在咱们可以用Hibernate来作些真正的工做。 


六 载入并存储对象

咱们最终可以使用Hibernate来载入和存储对象了。编写一个带有main()方法的StudentManager类: 

package com.test;

import org.hibernate.Session;
import com.model.StudentInfo;
import com.util.HibernateUtil;

public class StudentManager {
	
	public static void main(String[] args) {
		
		StudentManager mgr = new StudentManager();

		mgr.createAndStoreEvent();

        HibernateUtil.getSessionFactory().close();
    }

    private void createAndStoreEvent() {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        
        StudentInfo student = new StudentInfo();
        student.setName("无情");
        student.setAge(24);
        student.setSex("女");
        
        session.save(student);
        session.getTransaction().commit();
    }
}

咱们建立了个新的StudentInfo对象并把它传递给Hibernate。

现在Hibernate负责与SQL打交道,并把INSERT命令传给数据库。在执行以前。让咱们看一下处理Session和Transaction的代码。

 一个Session就是个单一的工做单元。咱们临时让事情简单一些,并若是HibernateSession和数据库事务是一一相应的。为了让咱们的代码从底层的事务系统中脱离出来(此例中是JDBC,但也多是JTA),咱们使用Hibernate Session中的Transaction API。 
sessionFactory.getCurrentSession()是干什么的呢?首先,仅仅要你持有SessionFactory(幸好咱们有HibernateUtil,可以随时得到),大可在不论何时、不论什么地点调用这种方法。

getCurrentSession()方法总会返回“当前的”工做单元。

记得咱们在hibernate.cfg.xml中把这一配置选项调整为"thread"了吗?所以,所以,当前工做单元被绑定到当前运行咱们应用程序的Java线程。但是。这并非是全然准确的,你还得考虑工做单元的生命周期范围 (scope),它什么时候開始,又什么时候结束. 
Session在第一次被使用的时候,即第一次调用getCurrentSession()的时候,其生命周期就開始。

而后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交仍是回滚,Hibernate会本身主动把Session从当前线程剥离。并且关闭它。倘若你再次调用getCurrentSession()。你会获得一个新的Session,并且開始一个新的工做单元。这样的线程绑定(thread-bound)的编程模型(model)是使用Hibernate的最普遍的方式,因为它支持对你的代码灵活分层(事务划分可以和你的数据訪问代码分离开来,在本教程的后面部分就会这么作)。 和工做单元的生命周期这个话题相关,Hibernate Session是否被应该用来运行屡次数据库操做?上面的样例对每一次操做使用了一个Session。这全然是巧合,这个样例不是很是复杂。没法展现其它方式。Hibernate Session的生命周期可以很是灵活。但是你毫不要把你的应用程序设计成为每一次数据库操做都用一个新的Hibernate Session。

七 Annotation注解方式

咱们用Annotation注解方式来取代XML配置方式。

在持久化对象时进行注解:

package com.model;

import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * Hibernate Annotation注解方式
 * @author xiaosi
 *
 */
//注解为一个实体
@ Entity
public  class TeacherInfo {
	private int id;
	private String name;
	private String sex;
	private int age;
	
	public TeacherInfo(){
	}
	//注解主键
	@ Id
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

在Hibernate.cfg.xml配置中:


启动辅助类中有一个不一样点:Configuration替换为AnnotationConfiguration

package com.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateAnoUtil {
	private static final SessionFactory sessionFactory;
    static 
    {
        try 
        {
            // Create the SessionFactory from hibernate.cfg.xml
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        }
        catch (Throwable ex) 
        {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

载入存储对象:

package com.test;

import org.hibernate.Session;

import com.model.TeacherInfo;
import com.util.HibernateAnoUtil;

public class TeacherManager {
	
	public static void main(String[] args) {
		TeacherManager mgr = new TeacherManager();
		mgr.createAndStoreEvent();
		HibernateAnoUtil.getSessionFactory().close();
	}

    private void createAndStoreEvent() {

        Session session = HibernateAnoUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        
        TeacherInfo teacher = new TeacherInfo();
        teacher.setId(1);
        teacher.setName("王倩");
        teacher.setAge(25);
        teacher.setSex("女");
        
        session.save(teacher);
        session.getTransaction().commit();
    }
}

数据库插入的数据:

相关文章
相关标签/搜索