Hibernate入门(第一天)

从今天开始学习hibernate。


hibernate是一个ORM持久层框架,所谓持久就是对数据的存储,放到文件里或者数据库中。ORM(object relationship mapping)指的是对象关系映射,实际上是为了解决面向对象与关系型数据库之间的不匹配现象的技术。对于初学hibernate的同学,你可以暂时理解它的作用是对JDBC的轻量级封装。

初学hibernate的时候,大家要重点关注hibernate的几个比较核心的类和接口,关注hibernate的配置文件内容,在运用熟练后再去了解hibernate的高级特性,这样学习效率会相对高一点。再就是建议大家循序渐进,学习框架之前一定要理解Servlet,jsp,JDBC等基本技术,不说精通,最起码的知识点要懂,然后自己有过练习,否则不适合学习框架。

现在直接说很多hibernate的特性或者好处初学者是体会不到的,总结的时候我再说吧,下面就我们通过一个简单的雇员管理系统的crud操作模块 来解释说明hibernate的特点和好处,同时大家可以对比一下hibernate和JDBC,Mybaties。

首先要先去下载hibernate依赖的jar包,现在的hibernate应该到4.2.2了,但是我这里要演示的是3.x系列,部分代码可能不一样(当初学mybaties的时候听说ibaties和它其实是一样的就是版本的问题结果发现其实很多类的使用和配置文件的设置还是有很多不一样的),这里请注意一下版本。

然后我们新建一个Java项目。在工程目录下建立一个lib文件夹,然后导入一下包


图上的这些包是必须的(那个hibernate-testing其实可以没有,测试用的),比如dom4j包是专门用来解析xml配置文件,学过框架的同学都知道,实际上所有框架都有一个共同的实现原理:就是通过反射技术动态的创建对象来实现很多操作,而具体怎么创建对象,什么样的策略,则是要读取相应的配置文件。因为框架不可能事先知道你有什么类要用,因此需要用户亲自配置(XML或者annotation),所以这个包肯定要有;

slf4j 和 log4j这俩包用得最多,用来做日志记录,hibernate在使用的时候是不要求用户自己写sql语句的(后面讲),那么其实这样对用户一个不好的地方就是我们不知道他对数据库是怎么操作的,因此日志就很重要了,有了日志我们就可以查看hibernate运行过程中用了哪些SQL语句。

其他包我就不太了解了,涉及到框架的设计需要的很多技术所以我没这个金刚钻也不揽瓷器活儿。接着往下讲。


这里插一句,我们在设计一个项目的时候,通常是这么一个流程:

先设计数据库,然后设计类实体模型,最后是对象关系映射文件的配置。

hibernate提出了一个新的设计方式:先设计类实体模型,然后是关系对象映射文件的配置,最后来设计数据库(其实如果配置文件设置好就不用设计数据库,能自动生成)。

一般国内的开发者习惯于前者(特别是没有框架前我们都是这么做,老外比较喜欢创新),所以我这里也用前者的方法来做。

我用的是mysql数据库,用其他数据库的童鞋,跟着思路操作也成。

1.创建一个数据库,名字叫employe ,然后新建一个表叫employee,字段 id(PK,int),name(varchar),email(varchar),hiedate(not-null,date)。

2.创建一个包:org.tute.pojo   pojo指的是简单的Java对象,就是JavaBean,在这个包里面创建一个类,名字叫Employee(这里注意,实体类的名字要和你要映射的数据库的表名对应起来,最好不要随便起,规范编码)

package org.tute.employsystem.pojo;

import java.io.Serializable;
import java.util.Date;

public class Employee implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String name;
	private String email;
	private Date hiredate;
	public Date getHiredate() {
		return hiredate;
	}
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	
}

这里我的Employee实现了Serializabe 这个类,使其能够被序列化。后面我在总结的时候说,那个序列化的ID是默认设置的,而不用改。

最后有一个比较大的步骤就是来配置hibernate的配置文件了。hibernate一般有这两种配置文件:hibernate.cfg.xml和Xxx.hbm.xml。第一个文件一个项目一般只有一个(看你用几个数据库,如果用两个的话也可以有两个),该配置文件主要内容就是设置你要用的数据库,用户名密码,连接池设置,关联对象关系映射文件,还有其他配置等等;

第二个文件在一个项目里也可以有很多(和mybaties里面的映射文件差不多,不过mybaties我习惯一个业务模块建一个),这个文件就是常提到的对象关系映射文件,这个文件里面通常会配置 我们指定的对象和数据表的关系,我们知道一个对象有很多的属性,比如id,name什么的,而数据库也有很多字段,这样我们会发现,其实一个表其实是可以和一个独对象产生映射关系的(后面再细说,别急哈太早解释会显得比较唐突),我们用这个配置文件来关联这二者使其产生联系。文件中能够设置那个属性和那个字段对应,主键设置,字段的属性等等。

3.新建一个Employee.hbm.xml文件,这个文件我们放在org.tute.pojo这个包下,然后配置该文件:

<?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 package="org.tute.employsystem.pojo">
	<class name="Employee" table="employee">
		<id name="id" column="id" type="integer">
			<generator class="increment"/>
		</id>
		<property name="name" type="string">
			<column name="name" not-null="false"/>
		</property>
		<property name="email" type="string">
			<column name="email" not-null="false" />
		</property>
		<property name="hiredate" type="date">
			<column name="hiredate" not-null="true" />
		</property>
	</class>
</hibernate-mapping>

这段配置文件我们一步步说。首先第一行我不解释,xml都有的;其次下面的dtd,有过xml知识的人都知道,一个xml文件想要遵守其规则,就要有一个类似于标准的文件,就是dtd了,有了这个dtd,我们下面的配置就能被约束住,否则程序员写错了也不知道哪里有问题,也能方便hibernate去读取这些配置。这个dtd不用我们写,我们去刚刚下载hibernate支持包的那个文件加,进入project文件夹,里面就有很多工程,随便进去找一个.hbm.xml文件打开复制来就好了(我再次强调一下,hibernate的版本和dtd版本一定要一样否则错了不怪我哦)。

复制来以后,我们在下面输入< 的时候,会发现eclipse能给我们自动提示了,方便我们配置,否则全盘手写也受不了。第一个标签<hiernate-mapping>这个标签的属性package写的是你的这个配置文件是要在那个包下面开始映射的,注意别写成类名了。

映射标签下面的标签是<class>,顾名思义就是类,这里就开始让大家配置 你指定的类和数据表的映射关系了。class标签的name属性写的是实体类的类名,因为你上一个标签指定了package了 这里就不用写全类名了。table这个也好理解,就是写你的表名(和数据库里面的表要对应起来)。

class里面的id标签,这个标签是用来设置主键映射的,name="id"这里的id是Employee类里面的id属性,column="id"则是指的表里面的id这个字段。 type是指定主键类型(不知道有什么类型的话alt / 看看就行)generator标签是配置主键的生成策略,主键生成策略有很多,不同数据库也有不同的生成方法,这里我们先用increment值。

下面就是配置其他属性和字段的映射,property和id这俩标签差不太多,看看就能理解,其内部column标签是配置表字段的。如果有哪些属性值大家不会写,就自动提示看一下有什么值,选一个就成。

4.配置hibernate.cfg.xml文件,该文件用来配置链接数据库类型、驱动、用户名密码等信息,管理映射文件。该文件我们配置好后一般不修改(前提是需求没变的话)。

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration >
    <session-factory>
    	<property name="hibernate.connection.driver_class ">com.mysql.jdbc.Driver</property>
    	<property name="connection.username">root</property>
    	<property name="hibernate.connection.password">******</property>
    	<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/employe</property>
    	<property name="show_sql">true</property>
    	<property name="hbm2ddl.auto">create</property>
    	<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  		<mapping resource="org/tute/employsystem/pojo/Employee.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

首先还是引入dtd,然后开始配置根元素<hibernate-factory>  <session-factory> 涉及到要配置数据库驱动类名,可能在切换数据库的时候是个麻烦,而且写property配置信息的时候你要配置什么信息,写的那个name也比较长,所以设计者会提供api,在下载源文件的project/etc/下,有一个hibernate.properties文件,这里面有很多属性直接粘贴过来用就行。还有一些别的配置信息比如show_sql这个值 是设置我们在使用hibernate的时候是否显示sql语句,hbm2ddl.auto这个值是指时候自动生成表(后面讲这个值的用法)。最后那个mapping我想大家肯定能猜到,就是管理映射文件。

5.业务层编写

现在我们开始模拟一个用户的添加过程。hibernate中比较重要的四个类:Configuration SessionFactory Session Transaction。在写业务层的时候也主要是这几个类。

代码如下:

</pre>public static void addUser() {<span style="white-space:pre">		</span>Session session = null;<span style="white-space:pre">		</span>Transaction trans = null;<span style="white-space:pre">		</span>try {<span style="white-space:pre">			</span>Configuration config = new Configuration().configure();<span style="white-space:pre">			</span>SessionFactory sessionfactory = config.buildSessionFactory();<span style="white-space:pre">			</span>session = sessionfactory.openSession();<span style="white-space:pre">			</span>trans = session.beginTransaction();<span style="white-space:pre">			</span>Employee employee = new Employee();<span style="white-space:pre">			</span>employee.setEmail("583110127@qq.com");<span style="white-space:pre">			</span>employee.setName("邢天宇");<span style="white-space:pre">			</span>employee.setHiredate(new Date());<span style="white-space:pre">			</span>employee.setId(100);<span style="white-space:pre">			</span>session.save(employee);<span style="white-space:pre">			</span>trans.commit();<span style="white-space:pre">		</span>} catch (HibernateException e) {<span style="white-space:pre">			</span>// TODO Auto-generated catch block<span style="white-space:pre">			</span>if(trans!=null){<span style="white-space:pre">				</span>System.out.println("事务回滚");<span style="white-space:pre">				</span>trans.rollback();<span style="white-space:pre">			</span><span style="white-space:pre">			</span>}<span style="white-space:pre">			</span>e.printStackTrace();<span style="white-space:pre">		</span>}finally{<span style="white-space:pre">			</span>if(session!=null&&session.isOpen())<span style="white-space:pre">				</span>session.close();<span style="white-space:pre">		</span>}<span style="white-space:pre">		</span><span style="white-space:pre">	</span>}<pre name="code" class="java">

第一步:创建Configuration.  Configuration config = new Configuration().configure();configure方法可以指定参数,参数信息是hibernate配置文件,如果不指定的话默认用hibernate.cfg.xml这个文件。
第二步:创建SessionFactory.   SessionFactory sessionfactory = config.buildSessionFactory();这是个重量级的类,比较耗费内存,一般将这个类设置为单例。
第三步:创建会话(Session),Session session = sessionfactory.openSession();这里的会话不同于servlet中的session,指的是和数据库的会话,相当于JDBC里面的Connection.

(这里注释一部,和mybaties一样,在进行对数据库的修改 类的操作,都需要使用事物提交)Transaction trans = session.beginTransaction();
第四步:添加一个记录。首先创建Employee对象,set进去姓名邮件雇用时间等属性(ID先不要管),session.save(employee).这个save方法其实在hibernate框架中的实现是一条insert语句,然后通过看你是什么数据库方言再对应翻译成什么样的SQL插入语句。
注意插入语句因为试图改变数据库内容,所以在这里要提交事务session.save(employee);
第五步:关闭资源  session.close();
执行后发现hibernate执行了一条select语句,查询主键最大值的,hibernate不需要我们设置主键就是在这里,它自动设置主键。


图片显示其实一个插入操作是要先查询的,查询当前主键最大值然后默认设置主键。


6.代码优化:

如果说我们平时都这么写代码显然是有问题的,首先性能上来说,SessionFactory是重量级的类,使用起来消耗内存;Configuration读取文件,也是比较消耗内存的,而且常理来说这两个类在一个项目中只存在一个实例就行了,所以我们要将其封装一下()和我们平时封装JDBC和mybaties一样做一个DBUtil。

package org.tute.employsystem.util;

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

final public class DBUtil {
	public static SessionFactory sessionFactory ;
	
	private DBUtil(){}
	static{
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}
	
	public static SessionFactory getSessionFactory(){
		return sessionFactory;
	}
}

将其设置为单例,并且防止继承。

下面我们还有一个需求,就是修改id为1的用户名和邮箱。

public static void updateEmploye() {
<span style="white-space:pre">		</span>Session session = DBUtil.getSessionFactory().openSession();
<span style="white-space:pre">		</span>Transaction trans  = null;
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>Employee employee = (Employee) session.load(Employee.class, 2);
<span style="white-space:pre">			</span>trans = session.beginTransaction(); 
<span style="white-space:pre">			</span>employee.setName("localhost");
<span style="white-space:pre">			</span>employee.setEmail("544324686@qq.com");
<span style="white-space:pre">			</span>trans.commit();
<span style="white-space:pre">		</span>} catch (HibernateException e) {
<span style="white-space:pre">			</span>// TODO Auto-generated catch block
<span style="white-space:pre">			</span>if(trans!=null)
<span style="white-space:pre">				</span>trans.rollback();
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}finally{
<span style="white-space:pre">			</span>if(session!=null&&session.isOpen())
<span style="white-space:pre">				</span>session.close();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}

首先我们先用session.laod(Employee.class,1),获得id为1的用户对象。然后我们对这个对象作相应的操作,set新的值,数据库表信息就相应修改了。

为什么会这样?这里说一下,hibernate把对象分成三个状态:瞬时态,持久态,离线态。我们的employe对象目前是处于持久态,因此我们对这个对象进行修改的时候连同数据库表信息就会一起修改。这也是hibernate的设计理念:将Java的面向对象和数据库的表联系起来,形成映射。

这里有必要提一下前面说的 给Employee实现Serializable接口的问题。实现了这个接口我们的类就能被序列化了,也就有了唯一标识,这样就能方便我们的表和类进行映射(开发规范,建议大家这么做,没什么害处),而且这样的类能够在网络中传输,能够写入文件。

删除也一样要先获取字段映射的对象,然后用delete方法就能达到目的。

public static void deleteUser() {
<span style="white-space:pre">		</span>Session session = DBUtil.getSessionFactory().openSession();
<span style="white-space:pre">		</span>Transaction trans = null;
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>trans = session.beginTransaction();
<span style="white-space:pre">			</span>Employee e = (Employee) session.load(Employee.class, 1);
<span style="white-space:pre">			</span>session.delete(e);
<span style="white-space:pre">			</span>trans.commit();
<span style="white-space:pre">		</span>} catch (HibernateException e) {
<span style="white-space:pre">			</span>// TODO Auto-generated catch block
<span style="white-space:pre">			</span>if(trans!=null)
<span style="white-space:pre">				</span>trans.rollback();
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">		</span>}finally{
<span style="white-space:pre">			</span>if(session!=null&&session.isOpen())
<span style="white-space:pre">				</span>session.close();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}


下面再说一下hibernate自动生成表的问题。前面提到过,hibernate开发者主张大家可以按照先设计对象模型再设计配置文件最后设计数据库的方法来开发,其实就是告诉我们开发者专注于开发,DBA专注于设计数据库,使得开发的时候每个人分工明确,甚至可以让我们程序员完全不要管数据库在做什么。

在hibernate.cfg.xml配置文件中,可以设置属性hbm2ddl.auto值为create,表示如果没有数据表则自动生成表(每次都会自动创建所以插入语句执行多次也只有一行数据,这里注意),表名字就是对象关系映射文件中,class里面的column属性的值 。注意如果切换了数据库一定要对象关系映射文件信息,特别是id标签里面的generator项生成策略,数据库之间各不相同所以要改好。这样创建的数据库中字段的属性是默认的,当然在hbm.xml文件中你可以指定数据列的字段信息比如length 指定varchar的长度等等;而且这种方式产生的数据库。



最后我们从一个初学者的角度来总结一下hibernate的特点,好处和不好。

持久层实际上是为了达到让对象模型和表结构统一关联的作用,传统的JDBC做法就是操作SQL语句然后将一个个字段填入语句中,驱动执行相应方法让这条语句在数据库生效,其麻烦也是可想而知,甚至还要面临需求更改,SQL语句大量的被替换的问题。

hibernate正是解决对象模型和数据表之间的隔阂,使其相互关联,并能够分离数据库和代码之间的耦合(我这里的意思是使程序员不再收到数据库的制约),能让开发者真正专注于业务层的编写。

如果大家还是不能理解hibernate的这个特点,我用我自己的理解举个例子:比如你是一个旅行者(代指开发者),你想去欧洲各国(代指各种数据库)游玩,但是你的目的是游玩(代指业务逻辑编写),可是期间需要和当地居民交流(代指编写SQL语句,对数据库数据表的操作),可是你只会中国话(HQL,这个以后的博客写),如果全程都是你自己给人家讲话,首先你要学会基本的所有国家的语言(了解不同数据库SQL语句还有特性等),其次你要会一些说话的技巧等等(合理封装JDBC)。那么如果你请一个导游(Hibernate)呢,这个导游精通各国语言,而且翻译的还很恰当(即配置里面的方言设定,设定数据库,并且SQL语句也是进行优化的),其次他能带你轻松走遍欧洲,去有名的景点,能给你省很多时间(其对象和表的映射功能,让你不用谢一个个resultset,然后循环....)。    这样去想hibernate,你能理解了吗?


那么hibernate的不好呢。

其一是,其实这个不能怪hibernate,因为你要有一个意识:只要你使用框架,性能肯定不如你不使用框架,比如你单纯用Servlet  jsp javabean做一个项目,这个项目的性能肯定比用 Spring  Springmvc Hibernate强,因为框架封装了这些操作,你使用这个操作的核心的时候实际上走了很多包装,就好比都说JAVA慢因为JAVA经过一道虚拟机所以慢。但是反过来想,其性能想对你不用框架也差不了太多,而且用框架方便管理和团队开发,其实还是利大于弊的。

第二个,初学者,特别是对JAVA掌握不好的初学者,你直接用hibernate可能对你没帮助,范围不利于你学习数据库,因为hibernate把数据库操作都封装完了,你是看不了其实质的(有源代码但是新手肯定看不明白吧),而且有些高手企图实现更优化的SQL语句,因此我觉得hibernate这个缺点是针对两个极端的,一个是新手(建议先学会基本的Servlet,jsp,JDBC再来学hibernate),再就是高手,高手们其实不用hibernate,人家自己封装持久层框架岂不更好。其实现在很多单位他们的持久层框架不用hibernate要自己做,顶多用Spring管理这些层。


hibernate的基础知识第一天到这里,有关hibernate的其他知识将在今后的博客更新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值