前言
对一个框架的直观认识,往往是从一个Hello World程序开始。Hibernate是一个ORM(Object Relationship Mapping)对象映射框架。实现了JDBC轻量级的封装,使得在进行JDBC开发的时候可以直接使用面向对象的思维进行开发,说白了Hibernate框架的作用是在Java对象与关系数据库中做了一个映射,使得程序员不用再使用各种SQL了。所以总结Hibernate以下几点:
1、完成了对JDBC的封装,不用再与各种Connection打交道了
2、在业务体系中是一个持久层框架(除了持久层还有业务层,主要使用Struts2或者SpringMVC完成,还有视图层,就是诸如jsp、freemarker啦这些显示信息的技术),对持久层的解释,我摘抄了官方的一句话:
Persistence simply means that we would like our application’s data to outlive the applications process. In Java terms, we would like the state of (some of) our objects to live beyond the scope of the JVM so that the same state is available later.
3、是一个ORM框架,不用与各种SQL打交道
Hibernate 入门程序:XML版
第一步:在myeclipse中创建一个web项目,取名为hibernate
第二步:在项目中添加使用Hibernate框架必须的jar包:如下图:
第三步:编写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>
<!-- 数据库连接配置 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/test</property>
<property name="connection.username">root</property>
<property name="connection.password">1234</property>
<!-- JDBC 连接池 -->
<property name="connection.pool_size">1</property>
<!-- SQL 方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- 禁用二级缓存 -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- 是否显示执行的SQL语句 -->
<property name="show_sql">true</property>
<!-- 删除并重建数据库 -->
<property name="hbm2ddl.auto">update</property>
<!-- 引入外部映射文件 -->
<mapping resource="bean/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>
上面的配置文件指明了一些必要的数据库连接属性,通过这些属性,Hibernate可以连接上数据库。可以配置各种不同的数据库,其中sql 方言属性指明了使用你所配置的数据库的sql语法(比如Oracle与MySQL中一些语法还是存在很大不同的)。
第四步:创建bean对象
package bean;
public class Person {
private int id;
private String sname;
private int age;
private float salary;
//无参构造方法,但是如果不写的话。Person类已经有一个默认的构造方法,那就是无参构造方法
public Person(){}
//省略get和set方法,这里把id的set方法设为private
private void setId(int id){
this.id = id;
}
@Override
public String toString() {
return "Person [id=" + id + ", sname=" + sname + ", age=" + age
+ ", salary=" + salary + "]";
}
}
这是一个标准JavaBean对象,Hibernate也建议我们这么写。但是在编写这个JavaBean的时候,有几点需要注意:一是对象的id属性,另一个是id属性的set方法。在Hibernate框架中,使用一个id为标识一个对象,所以在JavaBean中为一个对象添加id属性是必要的,因为在使用Hibernate框架时候,只有Hibernate才可以为一个对象分配id值(你可以试试在没有添加id属性的时候会出现什么异常)。另外,由于id是一个对象的标示符,所以我们一般禁止其他对象对这个属性进行随意的修改,所以将其set访问设为private也是出于这个层面的考虑。
第五步:编写Person.hbmxml映射文件,该文件的作用是把Java中的Bean对象与数据库中(确切说是RDBMS,关系数据库)中一条记录做了一个映射(这里就是ORM的关键),代码如下:
<?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="bean">
<class name="Person" table="PERSON">
<!--id就是指明对象标识符 name属性对应Person对象id属性
column表示该属性映射到数据表的哪个字段
-->
<id name="id" column="PERSON_ID">
<!-- 主键生成策略,native表示使用本地数据库的生成策略
比如这里使用的是MySQL,那么使用的主键策略就是MySQL的自动增长策略
-->
<generator class="native"/>
</id>
<!-- 普通属性name属性表示Person对象中的字段,type属性表示该属性的类型
当然也可以指明column属性,如果不知名,数据表中的字段与属性名称是一致的
-->
<property name="sname" type="java.lang.String"/>
<property name="age"/>
<property name="salary"/>
</class>
</hibernate-mapping>
创建JavaBean之后,就是上面的映射文件了,上面的文件名以及文件内容可能有一些难以理解的地方。首先我们得知道,一个映射文件(后缀hbm也正是hibernate映射文件的意思)的作用是什么?前面提到了Hibernate是一个对象映射框架,对象映射到哪里去了呢?当然是数据库中数据表的一条记录(一个对象映射到了数据库表的一条记录,就这么理解)了。那么这个映射的过程的实现就是通过上面的映射文件了。映射文件告诉Hibernate怎么样去加载和存储持久化类的对象,映射文件告诉Hibernate去数据库中的那张表寻找以及应该使用表中的哪些字段。
除此之外,我们注意到,有一些属性并没有指定type属性,有一些却指定了,那么什么类型属性需要指定,什么类型又不需要呢?对于一些常见的类型(
第六步:编写测试程序实现CRUD操作
package manager;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import utils.HibernateUtils;
import bean.Person;
public class PersonManager {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
// 创建一个Person对象并保存到数据库中
/*Person p = new Person();
p.setSname("赵云");
p.setAge(23);
p.setSalary(10000);
session.save(p);
// 开启事务并提交
t.commit();
// 查询
List list = session.createCriteria(Person.class).list();
for (Object object : list) {
Person pe = (Person) object;
System.out.println(pe);
}
// 更新
Person p2 = (Person) session.load(Person.class, new Integer(1));
p2.setSname("黄忠");
session.save(p2);
t.commit();
// 查询
List list2 = session.createCriteria(Person.class).list();
for (Object object : list2) {
Person pe = (Person) object;
System.out.println(pe);
}*/
//删除
Person p3 = (Person) session.get(Person.class, 2);
session.delete(p3);
t.commit();
}
}
在测试的时候,为了对每个操作是否成功进行测试,可以把其他程序注释。其中涉及了Hibernate一些核心类:SessionFactory、Session和Transaction。
1、SessionFactory
熟悉设计模式的小伙伴应该知道,这是典型的工厂模式,一个org.hibernate.SessionFactory工厂对象就是生成org.hibernate.Session实例的。在整个应用程序总一个org.hibernate.SessionFactory应该只被初始化一次,并且应该是线程安全的。所以上面的代码使用HibernateUtils类封装了SessionFactory实例,从而保证了整个应用期间,只有一个SessionFactory实例。这也是设计模式的一种——单例模式。对SessionFactory的解释我引用官方的一句话:
A threadsafe, immutable cache of compiled mappings for a single database. A factory for Session and a client of ConnectionProvider, SessionFactory can hold an optional (second-level) cache of data that is reusable between transactions at a process, or cluster, level.
下面是HibernateUtils.java的代码:
package utils;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
// 创建全局单一sessionFactory对象
private static final SessionFactory sessionFacoty = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory(){
return sessionFacoty;
}
}
2、Session
Session代表了一个工作单元,一个Session的产生往往是在事务开始的时候创建的,比如在调用getCurrentSession方法的时候,一个事务就开始了。通过这种方式获取的Session与openSession方法的不同在于前者在事务结束的时候就会自动关闭,所以在一个事务commit或者rollback的时候,该session对象就已经关闭了。而后者则可以一直生效,每次得到的Session都是一个新的对象。
Session is a single-threaded, short-lived object representing a conversation between the application and the persistent store. It wraps a JDBC connection and is a factory for Transaction. Session holds a mandatory first-level cache of persistent objects that are used when navigating the object graph or looking up objects by identifier.
3、Transaction
数据库中事务的概念是指访问并且可能更新数据项的程序执行单元,在sql编程中,一个事务可能是一条SQL查询语句。在Hibernate中,事务是与Session相关的。对此官方解释如下:
(Optional) A single-threaded, short-lived object used by the application to specify atomic units of work. It abstracts the application from the underlying JDBC, JTA or CORBA transaction. A Session might span several Transactions in some cases. However, transaction demarcation, either using the underlying API or Transaction, is never optional.