Hibernate是一个开放源代码的对象关系映射框架(ORM),它对JDBC进行了非常轻量级的对象封装,简化了java应用程序与数据库交互的开发。简化了数据创建,数据处理和数据访问。
- ①面向对象操作:将对数据库的操作转换为对Java对象的操作。
- ②数据库独立查询:通过配置对应的数据库“方言”,就可以根据不同类型的数据库生成适合的SQL语句。
- ③非侵入式:Hibernate不要求持久化类实现任何接口或继承任何类。
- ④快速性能:Hibernate框架内部使用缓存,支持查询缓存,因此性能很快。
- ⑤自动创建表:Hibernate框架提供了自动创建数据库表的功能。
- ⑥简化复杂连接:在hibernate框架中可轻松获取多个表中的数据。
- ⑦提供查询统计和数据库状态:Hibernate提供有关查询和数据库状态的统计信息。
一、ORM概念
对象关系映射(Object Relational Mapping,简称ORM),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
把对象表示的映射到基于SQL的关系模型数据库结构中去。在具体的操作实体对象的时候,就不需要再去和复杂的 SQ L 语句打交道,只需简单的操作实体对象的属性和方法。ORM 技术是在对象和关系之间提供了一条桥梁,对象型数据和数据库中的关系型的数据通过这个桥梁来相互转。
ORM技术特点:
- ①提高了开发效率。由于ORM可以自动将对象与数据库中的字段与属性的映射,所以已经不需要一个专用的、庞大的数据访问层。
- ②ORM提供了对数据库的映射,不用sql直接编码,能够像操作对象一样从数据库获取数据。
二、第一个hibernate
(一)Hibernate体系结构
Hibernate架构包括许多对象持久对象,会话工厂,事务工厂,连接工厂,会话,事务等。hibernate架构中有4层Java应用层,持久层,hibernate映射层和数据库层。
(二)引入相关jar包
需要引入hibernate的核心包和数据库连接包。只要到maven公库就能找到相应的jar包。我使用的以下版本:
(三)映射文件(**.hbm.xml)
1、创建实体类。
package org.ssh1.entity;
import java.util.Date;
/**
* 用来封装数据的实体类
*
* @author lee
*
*/
public class User {
private int id;
private String name;
private Date birthday;
//默认构造器
public User() {};
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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
2、映射文件
映射文件的名称必须和实体类一样,以 .hbm.xml
结尾。例如上面实体类的映射文件则为 User.hbm.xml 。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
映射文件
package属性:为该映射文件所在的包
-->
<hibernate-mapping package="org.ssh1.entity">
<!-- 实体类映射
name属性:对应实体类的全称,包名+类名
table属性:对应实体类的 数据库表名
-->
<class name="User" table="user">
<!-- 1、主键映射
name属性:实体类的成员变量
type属性:实体类的成员变量的类型
(可以为JAVA的类型 或 hibernate类型)
-->
<id name="id" type="int">
<!-- 字段映射
name属性:对应数据库的字段的名称
-->
<column name="id" />
<!-- 主键的生成策略 -->
<generator class="native" />
</id>
<!-- 2、普通字段映射
name属性:实体类的成员变量名称
type属性:实体类的成员变量的类型
-->
<property name="name" type="java.lang.String">
<!-- 字段映射
name属性:对应数据库的字段的名称
-->
<column name="name" />
</property>
<property name="birthday" type="java.util.Date">
<column name="birthday" />
</property>
</class>
</hibernate-mapping>
4、创建数据库
例如,上面实体类和数据库的对应
PS:实体类和映射文件必须在同一个包下面
PSPS : 实体类的成员变量 和 数据库的字段 名称可以不一样。
(四)配置文件(**.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>
<!-- 数据库连接配置 -->
<!-- 配置文件的问题一定要注意好.
hibernate有时候即使是配置错了,在一定的条件下也可以运行。
不要因此出现问题时,而不检查配置文件的问题。 -->
<!-- mysql驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- url -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<!-- 用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 密码 -->
<property name="hibernate.connection.password">qwertyuio</property>
<!-- 配置数据库的方言
根据不同的数据库,配置不同的方言。
通过这种方式,hibernate就可以以面向对象的形式来操作数据库,自动生成对应不同数据库的sql语句。
而不会因为数据库版本的不同而,而需要修改sql语句。
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--
是否打印出 执行的sql语句
-->
<property name="hibernate.show_sql">true</property>
<!-- 配置映射文件
resource属性:包名+映射文件名
file属性:如果不用resource属性,file属性要求是绝对路径。
-->
<mapping resource="org/ssh1/entity/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
(五)使用Hibernate
到了这里基本配置已经完成了。现在我们尝试使用hibernate来想数据库,保存一个对象到数据库中。
1、相关API
在使用hibernate前,我们先了解相关的API。
-
(1)Configuration类:负责管理 hibernate配置文件。
-
①Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应 hibernate.cfg.xml 文件)。
②持久化类与数据表的映射关系(*.hbm.xml 文件) -
①Configuration对象根据当前的配置信息生成 SessionFactory 对象。SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息。
②SessionFactory 对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存。 -
①Session是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,所有持久化对象必须在 session 的管理下才可以进行持久化操作。此对象的生命周期很短。
②Session 对象有一个一级缓存,显式执行 flush 之前,所有的持久层操作的数据都缓存在 session 对象处。相当于 JDBC 中的 Connection。持久化类与 Session 关联起来后就具有了持久化的能力 -
①代表一次原子操作,它具有数据库事务的概念。所有持久层都应该在事务管理下进行,即使是只读操作。
②session.beginTransaction() 开启事务
③commit() 提交事务
④rollback() 事务回滚
⑤wasCommitted() 检查事务是否提交
(2)SessionFactory类:
(3)Session类
(4)Transaction类
2、使用hibernate
package org.ssh1.dao;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import org.ssh1.entity.User;
public class Dao {
@Test
public void dao() {
//创建Configuratiion对象
Configuration config = new Configuration();
//加载配置文件
//(默认加载 src下的 hibernate.cfg.xml文件,也可以传入路径参数,加载其他的配置文件)
config.configure();
//创建一个Session工厂类
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = null;
Transaction trans = null;
try {
//创建一个会话
session = sessionFactory.openSession();
//开启事务
trans = session.beginTransaction();
//创建一个User对象,并添加一些信息
User user = new User();
user.setName("yang");
user.setBirthday(new Date());
//保存对象
//在这里我们可以看到,hibernate封装后的数据库操作,是以对象的形式来操作的
//不需要写任何的sql语句
session.save(user);
//提交事务
trans.commit();
}catch(Exception e) {
//出现异常,事务回滚
trans.rollback();
throw new RuntimeException(e);
}finally {
//关闭会话
session.close();
}
}
}
测试运行一下:
可以看到正确执行了,保存一个User对象到数据库中。hibernate,使程序脱离了繁琐的 JDBC的操作,以操作对象的形式来操作数据库。
PS:可能出现的异常:
Field ‘id’ doesn’t have a default value
数据库表中的主键没设置自动增长。也可以将主键的配置<generator class="native"/>
改为<generator class="assigned"/>
。
assigned是指主键是由人工分配的,native则指主键值由库自动给出。
三、hibernate 常用API
这里主要讲解如何使用 Session的方法来操作数据库。(相关的映射文件、配置文件、实体类、数据库和上面一样。)
(一)这里将hibernate的加载配置的方法,写到一个hibernate工具类中,方便我们使用。
package org.ssh1.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* hibernate工具类
*
* @author lee
*
*/
public class HibernateUtils {
public static SessionFactory sessionFactory ;
static {
Configuration config = new Configuration();
config.configure();
sessionFactory = config.buildSessionFactory();
}
public static Session openSession() {
return sessionFactory.openSession();
}
}
(二)使用相关的API
package org.ssh1.dao;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import org.ssh1.entity.User;
import org.ssh1.utils.HibernateUtils;
/**
* 相关的hibernate API 使用
*
* @author lee
*
*/
public class Dao {
//1、save 保存对象(数据)方法
@Test
public void testSave(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//因为id主键为自动增长,因此不需要指定id属性
User user = new User();
user.setName("qing");
user.setBirthday(new Date());
System.out.println("1、将一个对象保存到数据库当中:");
session.save(user);
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//2、update 更新对象(数据)方法
@Test
public void testUpdate(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//更新必须要有主键,当成员变量为null的时候,也会将对应的字段更新为null
//例如:下面的User对象没有设置 birthday属性,当执行更新操作,可以看到该条数据的birthday字段为null
User user = new User();
user.setId(100);
user.setName("xiao");
System.out.println("2、将指定id值的对象 更新到数据库中:");
session.update(user);
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//3、get 获取对象(数据)方法 (主键查询)
@Test
public void testGet(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//要查询对象(数据)的 id值
int id = 1;
System.out.println("3、根据 id 值获取指定的对象(数据):");
User user = session.get(User.class, id);
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//4、load 获取对象(数据)方法 (主键查询)(懒加载,就是用到时才会去查询。)
@Test
public void testLoad(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//要查询对象(数据)的 id值
int id = 1;
System.out.println("4、根据 id 值获取指定的对象(数据):");
User user = session.load(User.class, id);
user.getName();//这时候才会去数据库中查找数据(懒加载)
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//5、saveOrUpdate 保存或更新对象(数据)方法
@Test
public void testSaveOrUpdate(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//当该 对象的id值对应的数据,在数据库中存在时,则更新对象
//当该 对象没有设置id值 ,或id值对应的数据,在数据库中不存在时,则保存对象
User user = new User();
user.setId(99);
System.out.println("5、保存或更新一个对象(数据):");
session.saveOrUpdate(user);
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//6、delete 删除对象(数据)方法
@Test
public void testSaveOrUpdate(){
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//以传入一个id值来删除指定的对象(数据)
int id = 88;
System.out.println("6、删除一个对象(数据):");
session.delete(id);
trans.commit();
}catch(Exception e){
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
}
测试运行一下,可以看到结果:
四、hibernate 查询方法
hibernate的查询方式常见的主要分为三种: HQL查询,QBC(Criteria)查询,以及使用原生SQL查询。
(一)HQL查询(推荐使用)
HQL(Hibernate Query Language)是hibernate提供的面向对象的查询语言,在HQL中使用类名,而不是表名。所以是数据库独立的查询语言。
HQL查询提供了更加丰富的和灵活的查询特性,因此Hibernate将HQL查询方式立为官方推荐的标准查询方式,HQL查询在涵盖Criteria查询的所有功能的前提下,提供了类似标准SQL语句的查询方式,同时也提供了更加面向对象的封装。
HQL有很多优点。 它们如下:
- 数据库独立
- 支持多态查询
- 易于Java程序员学习
1、常用API
HQL查询主要是调用 Query对象的方法来实现。Query的对象可以通过Session接口调用createQuery()方法。常用的方法有:
//获取一个Query对象
Query query = session.creaeteQuery("HQL语句");
//将获取的结果作为列表返回
public List list()
//指定从哪里检索数据
public Query setFirstResult(int rowno)
//指定从表中检索数据的行数
public Query setMaxResult(int rowno)
//设置占位符的值
public Query setParameter(int position, Object value)
//设置占位符的值
public Query setParameter(String name, Object value)
2、常用的HQL查询方式
这里,我们介绍下一些常用的查询。
(查询所有、条件查询)(单个字段查询、单列查询、多列查询)(统计查询、分页查询)
package org.ssh1.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;
import org.ssh1.entity.User;
import org.ssh1.utils.HibernateUtils;
/**
* 常用的HQL查询
*
* @author lee
*
*/
public class Dao {
//1、查询所有
@Test
public void getAll() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/*
* 类似于SQL语句,但是通过操作对象来实现的。
* 例如,"from User" 中,"User" 不是数据表的名称,而是实体类的名称。
* 相对于sql语句 (select * from user) 来,还可以略写 "select * "
*
*/
//HQL语句 ,获取所有的 User对象
String HQL = "from User";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<User> query = session.createQuery(HQL);
//将获取的结果作为列表返回
List<User> users = query.list();
//输出从数据库获得的结果
System.out.println(users);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//2、条件查询
@Test
public void getPart() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的条件查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取字段 name为指定的值的 User对象
String HQL = "from User where name = ?";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<User> query = session.createQuery(HQL);
//设置第 1 个占位符的值(从0开始)
query.setParameter(0, "lee");
//query.setParameter("name","lee")//这种形式也是允许的
//获取 单一的一个 查询到的数据
User user = query.uniqueResult();
//输出从数据库获得的结果
System.out.println(user);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//3、单个字段查询
@Test
public void getSingleProperty() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的单个字段查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取指定 id值的对象的 name字段
String HQL = "select u.name from User u where id = ?";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<String> query = session.createQuery(HQL);
//设置第 1 个占位符的值(从0开始)
query.setParameter(0, 1);
//获取 单一的一个 查询到的数据
String name = query.uniqueResult();
//输出从数据库获得的结果
System.out.println(name);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//4、单列查询
@Test
public void getSingleColumn() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的单列查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取所有User对象的 name 字段
String HQL = "select u.name from User u ";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<String> query = session.createQuery(HQL);
//获取 多个查询到list集合
List<String> names = query.list();
//输出从数据库获得的结果
System.out.println(names);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//5、多列查询
@Test
public void getColumns() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的多列查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取所有User对象的 name 、id字段
String HQL = "select u.name,u.id from User u ";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<Object> query = session.createQuery(HQL);
//获取 多个查询到list集合
List<Object> results = query.list();
//输出从数据库获得的结果
//因为其返回的是一个集合,集合里面装的每一个元素是数组。
for(Object result :results ) {
Object[] res = (Object[]) result;
System.out.println(res[1]+" "+res[0]);
}
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//6、统计查询
@Test
public void getSum() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的统计查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取 数据的总数
String HQL = "select count(*) from User";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<Long> query = session.createQuery(HQL);
//获取 单一的一个 查询到的数据
Long count = query.uniqueResult();
//输出从数据库获得的结果
System.out.println(count);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//7、分页查询
@Test
public void getParts() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
/**
* 这里还有很多的分页查询,这里只是作为一个举例
*
*/
//HQL语句 ,获取所有的 User对象
String HQL = "from User";
//创建一个Query类
@SuppressWarnings("unchecked")
Query<User> query = session.createQuery(HQL);
//从第 2 行开始查询
query.setFirstResult(2);
//查询 10 行数据
query.setMaxResults(10);
//获取 单一的一个 查询到的数据
List<User> users = query.list();
//输出从数据库获得的结果
System.out.println(users);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
}
(二)Criteria查询
Criteria(QBC query by criteria,完全面向对象的查询)提供了一种面向对象的方式查询数据库。
package org.ssh1.dao;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import org.ssh1.entity.User;
import org.ssh1.utils.HibernateUtils;
/**
*
* Criteria查询(只做简单的介绍)
* 更多关于Criteria查询可以查看其 API,进行更深度的学习
*
* @author lee
*
*/
public class CriteriaDao {
//1、获取所有的 User对象
@Test
public void getAll() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//可以看到 criteria的查询中 看到任何的类似sql的语句,完全地面向对象开发
//但是需要了解很多的API
//传入一个 类的class属性
Criteria qbc = session.createCriteria(User.class);
//获取所有
@SuppressWarnings("unchecked")
List<User> list = qbc.list();
//输出获取的结果集
System.out.println(list);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//2、条件查询
@Test
public void getPart() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//传入一个 类的class属性
Criteria qbc = session.createCriteria(User.class);
//获取指定 id 值的User
qbc.add(Restrictions.eq("id", 1));
@SuppressWarnings("unchecked")
User user = (User) qbc.uniqueResult();
//输出获取的结果集
System.out.println(user);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
}
(三)本地SQL查询
多用于使用于复杂的查询,就是使用原生态的sql查询。(不能跨数据库平台)
package org.ssh1.dao;
import java.util.List;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import org.ssh1.entity.User;
import org.ssh1.utils.HibernateUtils;
/**
*
* SQL查询(只做简单的介绍)
* 更多关于SQL查询可以查看其 API,进行更深度的学习
*
* @author lee
*
*/
public class CriteriaDao {
//1、获取所有的 User对象
@SuppressWarnings("deprecation")
@Test
public void getAll() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//传入一个 sql 语句
SQLQuery sql = session.createSQLQuery("select * from user");
//获取所有
@SuppressWarnings("unchecked")
List<User> list = sql.list();
//输出获取的结果集
System.out.println(list);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
//2、条件查询
@SuppressWarnings("deprecation")
@Test
public void getPart() {
Session session = null;
Transaction trans = null;
try {
session = HibernateUtils.openSession();
trans = session.beginTransaction();
//传入一个sql语句
SQLQuery sql = session.createSQLQuery("select * from user where id=1");
@SuppressWarnings("unchecked")
User user = (User) sql.uniqueResult();
//输出获取的结果集
System.out.println(user);
trans.commit();
}catch(Exception e) {
trans.rollback();
throw new RuntimeException(e);
}finally {
session.close();
}
}
}
PS:编写 hibernate的 映射文件 和 配置文件,要自己编写过于麻烦。可以在开发集成环境中,添加在 JBoss Tools插件,来帮助我们。