Hibernate快速入门之CRUD
一、Hibernate的基本概念
前言
Hibernate是一个ORM框架,ORM是Object Relational Mapping的缩写,即对象关系映射,也就是将面向对象思想的编程语言与关系型数据库进行映射,让开发者可以用面向对象的思想来进行数据库的增删改查操作。
比如,Java是面向对象的语言,MySQL是关系型数据库,ORM框架就是将这两者进行映射。
当下主流的ORM框架除了Hibernate,还有Mybatis。
1.Hibernate简介
Hibernate对数据库结构提供了校完整的封装,Hibernate的O/R Mapping实现了POJO和数据库表之间的映射,以及SQL的自动生成和执行。我们往往只需定义好了POJO到数据库表的映射关系,即可他那个个Hibernate提供的方法完成持久层操作。程序员甚至不需要对SQL的熟练掌握,Hibernate/OJB会根据制定的存储逻辑,自动生成对应的SQL并调用JDBC接口加以允许。
2.Hibernate和MyBatis的区别
MyBatis简介:MyBatis的着力点,在于POJO 与SQL之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。
区别:
- Hibernated 的设计理念完全是面向POJO的,而MyBatis不是。
- Hibernate基本不需要我们编写SQL语句就可以通过映射关系来操作数据库,是一种全表映射的体现,而MyBatis需要我们提供SQL去运行。
- 在复杂查询的情况下,由于无需SQL,通过Hibernate查询会造成很多的性能丢失。而MyBatis不会,因为MyBatis可以自由书写SQL、支持动态SQL、处理列表、动态生成表名,支持存储过程。非常的灵活,可以满足各类需求和性能优化。
在管理系统时代,Hibernate是主流
因为在管理系统中,首先是实现业务逻辑,然后才是性能。
在移动互联网时代,MyBatis是首选
因为MyBatis不屏蔽SQL,程序员可以自己制定SQL规则,能更加精确定义SQL,从而优化性能。更符合移动互联网高并发,大数据,高性能,高响应的要求。
二、Hibernate的使用
了解完Hibernate的基本概念,接下来讲解如何使用。简单分为五个步骤:
1.导入相关jar包(两组jar包,一组Hibernatejar包,一组Oracle驱动jar包)。
2.创建Hibernate配置文件。
3.创建实体类。
4.创建实体-关系映射文件。
5.调用HibernateAPI对数据库进行管理。
1.添加相关依赖
我是创建了一个maven项目,所以需在pom.xml文件中导入以下依赖
<!-- Oracle的jdbc驱动包 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>12.1.0.2.0</version>
</dependency>
<!-- 添加Hibernate依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.10.Final</version>
</dependency>
<!-- 添加Log4J依赖 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.6.4</version>
</dependency>
<!-- 添加javassist -->
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.0.GA</version>
</dependency>
2.创建配置文件
2.1.在项目中添加Hibernate,Ctrl+ALT+Shift+S
2.2.生成hibernate.cfg.xml配置文件,点击+号然后会出来一个文件
在resources中会生成一个怎样的配置文件
3.配置hibernate.cfg.xml
接下来就是配置Hibernate的属性了,这里我配置了这些属性
<session-factory>
<!--配置Oracle连接数据库的基本信息-->
<property name="connection.username">Li</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<!--每个数据库都有其对应的方言(Dialect)以匹配其平台特性-->
<property name="dialect">
org.hibernate.dialect.Oracle10gDialect
</property>
<!--指定当前session范围和上下文-->
<property name="current_session_context_class">thread</property>
<!--是否将运行期生成的SQL输出到日志以供调试-->
<property name="show_sql">true</property>
<!--是否格式化SQL-->
<property name="format_sql">true</property>
</session-factory>
简单介绍一下之前没见过的参数:
-
dialect:
用于配置Hibernate的数据库类型。Hibernate支持几乎所有的主流数据库,包括Oracle、DB2、MS SQL Sserver 和Mysql等。org.hibernate.dialect.Oracle10gDialect指定当前数据库类型是Oracle 10g及以上版本。current_session_context_class
-
current_session_context_class:
指定org.hibernate.context.CurrentSessionContext.currentSession()方法所得到的Session由谁来管理。thread指Session由当前执行的线程来跟踪管理。
-
show_sql:
如果设置为true,则程序运行时在控制台输出SQL语句。
-
format_sql:
如果设置为true,则程序运行时在控制台输出格式化后的SQL语句。
4.创建持久化类和映射文件
4.1 实体类
注意事项:
-
必须有一个无参构造函数
因为Hibernate查询出数据需要将数据封装到一个对象中,底层通过反射机制调用无参构造创建对象,所以必须提供无参构造函数,否则代码报错。
-
提供一个标识属性,表的主键
此属性一般定义为id,int类型,与业务无关,只是用来标识对应表的主键。
-
类的所有属性都要有getter和setter方法
Hibernate通过setter方法将查询出的字段值分别赋给对应对象的各个属性,通过getter方法取属性值,若没有gtter和setter方法,直接报错,必须同时拥有这两个方法。
-
建议为实体类实现java.io.Serializable接口,这并不是Hibernate所要求的,为了在将持久化类用于数据传输等用途时能够对其实例正确执行序列化操作。
部门持久化类Dept.java的代码:
@Data
public class Dept implements Serializable {
private Byte deptNo;
private String deptName;
private String location;
}
4.2 实体映射关系文件
创建持久类后,Hibernate会根据此文件将持久化类和数据库进行关联,需要“告诉”Hibernate,持久化类映射到数据库的哪个表,以及哪个属性对应到数据库表的哪个字段,这些都要在持久类的映射文件中配置。此文件与持久化类在同一包下。
注意:在Hibernate中,映射文件通常与对应的持久化类同名,并以“.hbm.xml”作为后缀。
特别注意:Maven默认的只编译加载resources目录的配置文件,如果把文件放在了java目录下,需要在pom.xml中添加如下配置(eclipse中可能不会出现这种情况)
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--在dept包下-->
<hibernate-mapping package="com.lily.pojo.dept">
<!--类名为Dept,表名为DEPT-->
<class name="Dept" table="`DEPT`">
<!--主键映射,属性名为deptNo,列名为DEPTNO-->
<id name="deptNo" type="java.lang.Byte" column="`DEPTNO`">
<!--主键由应用程序负责生成,无需Hibernate参与。这是指定<generator>元素时的默认生成策略-->
<generator class="assigned"/>
</id>
<!--非主键映射,属性和列名一一对应-->
<property name="deptName" type="java.lang.String" column="`DNAME`"/>
<property name="location" type="java.lang.String" column="LOC"/>
</class>
</hibernate-mapping>
映射文件定义完毕,还需要在配置文件hibernate.cfg.xml中声明
<session-factory>
<!--其他配置文件省略-->
<!--映射文件配置,注意文件名必须包含相对于classpath的全路径-->
<mapping resource="hbm/Dept.hbm.xml"/>
</session-factory>
4.3 操作数据库的七个步骤
-
读取并解析配置文件及映射文件。
//获取加载配置管理类 Configuration configuration = new Configuration(); //不给参数就默认加载hibernate.cfg.xml文件, configuration.configure();
-
依据配置文件和映射文件中的信息,创建SessionFactory对象。
//创建Session工厂对象 SessionFactory factory = configuration.buildSessionFactory();
-
打开Session
//得到Session对象 Session session = factory.openSession(); //或者 factory.getCurrentSession();
-
开启事务
//使用Hibernate操作数据库,都要开启事务,得到事务对象 Transaction transaction = session.beginTransaction();
-
数据库操作
//把对象添加到数据库中 session.save(user);
-
结束事务
//提交事务 transaction.commit(); 或 //回滚事务 transaction.rollback();
-
如果是通过SessionFactory的openSession()方法获取的Session对象,则需要关闭session
session.close();
ps:如果在Hibernate配置文件中将参数current_session_context_class设置为thread,并采用SessionFactory的getCurrentSession()方法获得Session对象,则不需要执行session.close()方法,通过这种方式获得的Session对象,会在管理的事务结束(提交或回滚)时自动关闭。
4.4 管理SessionFactory和Session工具类
在项目开发过程中,通常使用工具类来管理SessionFactory和Session,代码如下
public class HibernateUtil {
private static Configuration configuration;
private static SessionFactory sessionFactory;
//初始化Configuration和SessionFactory
static {
try {
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
} catch (HibernateException e) {
e.printStackTrace();
}
}
private HibernateUtil(){}
//获取Session对象
public static Session currentSession(){
return sessionFactory.getCurrentSession();
}
}
在此工具类中,采用SessionFactory的getCurrentSession()方法获取Session对象,结合Hibernate配置文件中的如下设置:
<property name="current_session_context_class">thread</property>
三、 增删改查示例
为了简化编码我们可以定义一个DAO基类,对获得Session方法调用进行封装,代码如下
public class BaseDao {
public Session currentSession(){
return HibernateUtil.currentSession();
}
}
1. DAO层
public class DeptDao extends BaseDao {
/**
* 根据主键查询,传入对应的class和id就可以查询
* @param id 主键id
* @return 实体对象
*/
public Dept get(Serializable id){
//通过Session的get()方法根据OID加载指定对象
return (Dept) currentSession().get(Dept.class,id);
}
/**
* 根据主键查询,支持懒加载
* @param id 主键id
* @return 查询的实体
*/
public Dept load(Serializable id){
//通过Session的load()方法根据OID加载指定对象
return (Dept) currentSession().load(Dept.class,id);
}
/**
* 保存
* @param dept 实体对象
*/
public void save(Dept dept){
currentSession().save(dept); //保存指定的Dept对象
}
/**
* 删除
* @param dept 实体对象
*/
public void delete(Dept dept){
currentSession().delete(dept); //删除指定的Dept对象
}
}
2. Service层
@Data
public class DeptBiz {
private DeptDao deptDao = new DeptDao();
/** 根据id查找
* @param id 主键id
* @return 实体对象
*/
public Dept findDeptById(Byte id){
Transaction tx = null;
Dept result = null;
try {
//开启事务
tx = HibernateUtil.currentSession().beginTransaction();
result = deptDao.get(id); //调用Dao方法,根据OID加载指定Dept对象
//输出结果,与调用get()方法时不同,须在关闭会话前测试查询效果
//提交事务
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();//回滚事务
}
}
return result;
}
/**
* 添加
* @param dept 实体对象
*/
public void addNewDept(Dept dept){
Transaction tx = null;
try {
tx = deptDao.currentSession().beginTransaction(); //开启事务
deptDao.save(dept);
tx.commit(); //提交事务
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback(); //回滚事务
}
}
}
/**
* 修改
* @param dept 实体对象
*/
public void updateDept(Dept dept){
Transaction tx =null;
try {
tx = deptDao.currentSession().beginTransaction(); //开启事务
//加载要修改的部门对象
Dept deptToUpdate = deptDao.load(dept.getDeptNo());
//更新部门数据
deptToUpdate.setDeptName(dept.getDeptName());
deptToUpdate.setLocation(dept.getLocation());
//提交事务
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback(); //回滚事务
}
}
}
/**
* 删除
* @param id 主键id
*/
public void deleteDept(Byte id){
Transaction tx = null;
try {
tx = deptDao.currentSession().beginTransaction(); //开启事务
//加载需删除的部门对象
Dept deptToDelete = deptDao.load(id);
deptDao.delete(deptToDelete);
tx.commit(); //提交事务
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback(); //回滚事务
}
}
}
}
3. 测试类
public class CRUDTest {
DeptBiz deptBiz =new DeptBiz();
/**
* 查询
*/
@Test
public void testGetAllById(){
//1.加载数据操作
Dept dept = deptBiz.findDeptById(new Byte("10"));
//2.输出数据
System.out.println(dept.getDeptName());
}
/**
* 添加
*/
@Test
public void testAddDept(){
//构建测试数据
Dept dept = new Dept();
dept.setDeptNo(new Byte("11"));
dept.setDeptName("测试部");
dept.setLocation("东区");
//保存新部门信息
deptBiz.addNewDept(dept);
}
/**
* 修改
*/
@Test
public void testUpdateDept(){
//构建测试数据
Dept dept = new Dept();
dept.setDeptNo(new Byte("11"));
dept.setDeptName("质管部"); //发生变化
dept.setLocation("东区");
//更新
deptBiz.updateDept(dept);
}
/**
* 删除
*/
@Test
public void testDeleteDept(){
deptBiz.deleteDept(new Byte("11"));
}
}
总结:
Hibernate作为一个主流的ORM框架,我们需要学会怎样去使用。框架的使用很简单,可以将其理解为一个别人封装好的工具交给你来使用,所以单纯开发的角度讲,我们只需要学会怎样去使用框架,按照作者指定的方式去进行开发即可。当然,底层的原理最好也需要简单的理解,多关注,多思考,对提供我们自己的编程思想是有很大的帮助的。