##概述
在JPA和ORM介绍中说到,Hibernate框架属于JPA框架中的一种,是基于ORM思想实现的持久化框架。
Hibernate是一个开源的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将Java Model类与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
##准备工作
在使用JDBC连接数据库之前,首先要有数据库,数据库要创建表。我的数据库信息如下:
- 数据库类型:MySql。
- 数据库名字:xia。
- 用户名:root。
- 密码:root.
- 创建数据库表student。
create table student(
id int primary key auto_increment,
name varchar(20),
age int
);
##开发环境
- 操作系统:MACOS。
- 开发工具:IntelliJ IDEA。
- Java版本:jdk1.8。
- 使用maven管理jar包。
##正式开发
一,在pom.xml文件中引入需要jar的依赖
<!--mysql驱动,连接mysql的操作都需要mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!-- hibernate-core包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.16.Final</version>
</dependency>
二,创建对象与表结构映射关系文件
<?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>
<!--
class用来描述一个类
name 类的全名
table 该持久化类对应的表名 可以不写,默认值为类名
-->
<class name="com.honor.sql.Student" table="student">
<!--
Student类字段与表结构字段对应关系
name 属性的名称
column 属性的名称对应的表的字段 可以不写 默认值就是属性的名称
length 属性的名称对应的表的字段的长度 如果不写,默认是最大的长度
-->
<id name="id" column="id" length="5">
<!-- 主键的产生器 -->
<generator class="increment"></generator>
</id>
<property name="name" column="name" length="20" ></property>
<property name="age" column="age" length="50" ></property>
</class>
</hibernate-mapping>
注:
- 映射关系表通常以“表名.hbm.xml”的格式命名。也可以自定义,只要在hibernate的配置文件中指定即可。
- 在映射关系表中指定了Model类与表名的对应关系,及Model类字段与表结构字段的对应关系。
- 通常一个表对应一个Model类,需要写一个映射关系文件。
三,创建hibernate框架的全局配置文件
全局配置文件也放在resource目录下,命名为: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>
<!-- 一个sessionFactory代表数据库的一个连接-->
<session-factory>
<!-- 链接数据库的用户名 -->
<property name="connection.username">root</property>
<!-- 链接数据库的密码 -->
<property name="connection.password">root</property>
<!-- 链接数据库的驱动 -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- 链接数据库的url -->
<property name="connection.url">
jdbc:mysql://localhost:3306/xia
</property>
<!--方言,告诉hibernate使用什么样的数据库,hibernate就会在底层拼接什么样的sql语句-->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!--
配置根据持久化类生成表的策略
validate 通过映射文件检查持久化类与表的匹配
update 每次hibernate启动的时候,检查表是否存在,如果不存在,则创建,如果存在,则什么都不做了
create 每一次hibernate启动的时候,根据持久化类和映射文件生成表
create-drop
-->
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<!--加载model类与表结构映射关系文件-->
<mapping resource="student.hbm.xml" />
</session-factory>
</hibernate-configuration>
注:该文件的主要作用有两个:
- 配置数据库参数,账号、密码、数据库驱动等信息。
- 配置model类与表结构映射关系文件
注:hibernate框架具有创建表结构的功能,在hbm2ddl.auto属性中指定update即可。但在项目中我一般都是手动创建表结构。
四,得到Session对象
/**
* 根据配置文件获取Session对象
*
* @return
*/
public static Session getSession() {
//加载hibernate全局配置文件
Configuration cfg = new Configuration().configure("/hibernate.cfg.xml");
SessionFactory factory = cfg.buildSessionFactory();
//得到Session对象,所有的数据库操作都是通过Session对象来完成
Session session = factory.openSession();
return session;
}
五,插入操作
public static boolean insertStudent(Student student) {
//获取Session对象
Session session = getSession();
try {
//开始事务
session.beginTransaction();
//插入数据,此时在student.hbm.xml文件中指定Student类对应student表,所以会将student对象数据插入到student表中
session.save(student);
//提交事务
session.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return false;
}
六,根据id查找单个对象
public static Student selectStudent(int id) {
//获取Session对象
Session session = getSession();
try {
session.beginTransaction();
//根据id查询Student对象
Student student = session.load(Student.class, id);
session.getTransaction().commit();
return student;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return null;
}
七,注意Hibernate的懒加载机制
调用上面方法根据id查找对象,代码如下:
Student student = selectStudent(9);
String name = student.getName();
此时报了下面异常:
然后我一行一行的debug,发现居然没有问题,瞬间感觉异常的神奇。
网上各种查找资料才知道hibernate框架中使用的懒加载机制,简单说就是:hibernate使用session管理,查询数据时创建一个session对象,当执行查询代码时只是查找到数据的引用,当用到数据时再加载。但如果把session关闭后再使用数据就会报上面异常。
解决方法:
- 在关闭懒加载。
- 数据使用完成后再关闭session。
##1,关闭懒加载的方法
在关系映射文件的class标签中设置lazy="false",如下:
<class name="com.honor.sql.Student" table="student" lazy="false">
注:这种方式去除了hibernate节约资源的机制,不建议使用。
##2,数据使用完成后再关闭session
在JavaWeb项目中使用时可以设置Filter统一关闭session
<filter-name>hibernateFilter</filter-name>
<filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class>
</filter
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在springMVC框架中可以设置拦截器:
<mvc:interceptors>
<bean class="org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</mvc:interceptors>
八,根据其他条件得到对象集合
public static List<Student> selectStudentList(int age) {
//获取Session对象
Session session = getSession();
try {
session.beginTransaction();
//定义hql语句,类似于sql语句,注意:此时Student是对象,并不是表名。在student.hbm.xml文件中指定Student类对应student表
String hql = " from Student where age = " + age;
Query query = session.createQuery(hql);
List<Student> studentList = query.list();
session.getTransaction().commit();
return studentList;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return null;
}
九,更新操作
public static boolean updateStudent(Student student) {
//获取Session对象
Session session = getSession();
try {
session.beginTransaction();
//根据ID更新数据
Student studentResult = session.load(Student.class, student.getId());
//更新Name
studentResult.setName(student.getName());
//执行更新操作
session.update(studentResult);
session.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return false;
}
十,删除操作
public static boolean deleteStudent(int id) {
//获取Session对象
Session session = getSession();
try {
session.beginTransaction();
//根据ID得到Student对象
Student student = session.load(Student.class, id);
//删除操作
session.delete(student);
session.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return false;
}
##在Hibernate框架中使用sql语句操作数据库
在Hibernate框架中完全不用写sql语句就可以进行数据库的增删改查,但也可以使用sql语句。下面以查询操作为例说明怎么在Hibernate框架中使用sql语句。
public static List<Student> selectStudentListBySql(int age) {
//获取Session对象
Session session = getSession();
try {
session.beginTransaction();
//写sql语句,由于在student.hbm.xml文件中指定Student类对应student表,所以会把结果封装到Student对象中
String sql = "select id,name,age from student where age = " + age;
Query query = session.createSQLQuery(sql);
List<Student> studentList = query.list();
session.getTransaction().commit();
return studentList;
} catch (Exception e) {
e.printStackTrace();
//出现异常时回滚事务
session.getTransaction().rollback();
} finally {
if (session != null) {
if (session.isOpen()) {
session.close();//关闭session
}
}
}
return null;
}
注:
- sql语句与hql不同,sql中使用的是表名student,hql中使用的是类名Student。
- 执行sql使用的是Session类的createSQLQuery方法,执行hql使用的是Session类的createQuery方法。
##总结
- 对JDBC进行了封装,使用了数据库连接池,更便于使用。
- 隐藏sql,将对数据库的操作转化为对对象的操作,实现面向对象编程。
- hibernate提供了缓存机制,一级缓存,二级缓存,查询缓存。
- 封装了sql与对象的映射,通过操作对象实现操作sql,故比直接操作sql效率低。
- 框架封装了sql,直接操作对象,导致对sql操作对自由度降低,尤其对多表查询操作受限。
- 表中的数据如果在千万级别,则hibernate不适合。
- 如果表与表之间的关系特别复杂,则hibernate也不适合。
Hibernate的使用场景:
由于Hibernate不适合大量数据,所以一般用在企业内部的系统,比如公司内网。不适用于对外公共的网络,比如淘宝,京东这样的公司。