前言:最近上班工作不忙,随手写了几个demo,贴出来,供初学者学习一下
一.hibernate 简介:
hibernate是一个开源框架,它是对象关联关系映射的框架,它对JDBC做了轻量级的封装,而我们java程序员可以使用面向对象的思想来操纵数据库。
Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。简化DAO层的编码工作
Hibernate的底层也是使用的sql代码实现的。
二.新建项目的步骤
A.第一步,导入项目所需的jar包。
导入新下载的jar\hibernate-release-5.3.0.Final\hibernate-release-5.3.0.Final\lib\required下的所有的jar文件即可
B.新建hibernate核心配置文件hibernate.cfg.xml(放在src目录下,文件位置固定)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 1数据库信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///mydb3</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">000000</property>
<!-- 2.hibernate 其他配置-->
<!-- 配置事务的隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
<!-- 显示底层sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 输出底层sql语句格式 -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate会自动创建表
update:若表存在则更新,没有则创建
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库方言,做分页的时候会使用到
让hibernate框架识别不同的数据库
方言一定要写成这样不能修改其他的 否则无法创建表
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 配置 Session 绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入配置文件 -->
<mapping resource="com/ies/entity/Car.hbm.xml"/>
<mapping resource="com/ies/entity/People.hbm.xml"/>
</session-factory>
</hibernate-configuration>
C.新建实体类,模拟人和车之间的关系。一个人可以有多个车,一个车只能属于一个人。多---》车,一---》人
1.Car实体类
package com.ies.entity;
/*
* car
*/
public class Car {
private Integer cid;
private String cname;
private String cage;
private People people;
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getCage() {
return cage;
}
public void setCage(String cage) {
this.cage = cage;
}
public People getPeople() {
return people;
}
public void setPeople(People people) {
this.people = people;
}
@Override
public String toString() {
return "Car [cname=" + cname + ", cage=" + cage + "]";
}
}
2.People.java
package com.ies.entity;
import java.util.HashSet;
import java.util.Set;
/*
* people
*/
public class People {
private Integer pid;
private String pname;
private String page;
private Set<Car> setCar = new HashSet<>();
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public Set<Car> getSetCar() {
return setCar;
}
public void setSetCar(Set<Car> setCar) {
this.setCar = setCar;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
@Override
public String toString() {
return "People [pname=" + pname + ", page=" + page + "]";
}
}
D.配置两个实体类的文件。
1.Car.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ies.entity.Car" table="t_car">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="cname" column="cname"></property>
<property name="cage" column="cage"></property>
<!-- name:少的一方在多的一方类中的表示
column:外键
class:外键所指的类名
-->
<many-to-one name="people" column="pid" class="com.ies.entity.People"></many-to-one>
</class>
</hibernate-mapping>
2.People.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ies.entity.People" table="t_people">
<id name="pid" column="pid">
<generator class="native"></generator>
</id>
<property name="pname" column="pname"></property>
<property name="page" column="page"></property>
<set name="setCar" cascade="save-update,delete">
<!-- 一对多,有外键,
hibernate机制:双向维护外键,在一和多那一方都配置外键
key的column属性表示外键名称
-->
<key column="pid"></key>
<one-to-many class="com.ies.entity.Car"/>
</set>
</class>
</hibernate-mapping>
E.编写工具类,用来放回hibernate中sessionFactory对象和session对象
package com.ies.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibnernateUtil {
private static SessionFactory sessionFactory = null;
static {
Configuration cfg = new Configuration();
cfg.configure();
/**
* 创建session的对象
* 读取核心配置文件的内容。
* 会根据映射关系,在数据库里把表创建
*/
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session openSession() {
return sessionFactory.openSession();
}
public static Session currentSession() {
return sessionFactory.getCurrentSession();
}
public static void main(String[] args) {
}
}
在这里说明一下,hibernate 中核心配置文件中<property name="hibernate.hbm2ddl.auto">update</property>这句话的意义。
在hibernate核心配置文件加载时,会产生sessionFactory对象,sessionFactory会自动检测数据库中是否有需要创建的表,若没有则创建。也就是说,当我们运行HibnernateUtil.java这个类的时候,会在数据库中创建两个表以及他们之间的关系。
F.编写测试类
package com.ies.test;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;
import com.ies.entity.Car;
import com.ies.entity.People;
import com.ies.util.HibnernateUtil;
public class OneToManyTest {
private SessionFactory sessionFactory = null;
private Session session = null;
private Transaction transaction = null;
/*
* add
*/
@Test
public void addCar() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
People people = new People();
people.setPname("tom");
people.setPage("2222");
Car car = new Car();
car.setCname("car1");
car.setCage("1111");
people.getSetCar().add(car);
// car.setPeople(people);
Car car2 = new Car();
car2.setCname("car2");
car2.setCage("2222");
// car2.setPeople(people);
people.getSetCar().add(car);
// session.save(car);
// session.save(car2)
session.save(people);
transaction.commit();
}catch (Exception e) {
if(transaction!=null) {
transaction.rollback();
}
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
/*
* 删
*/
@Test
public void testDelete() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
/*
* 先查后删
*/
People people = session.get(People.class, 2);
session.delete(people);
transaction.commit();
}catch (Exception e) {
transaction.rollback();
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
/*
* update
*/
@Test
public void testUpdate() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
/*
* 先查后改
*/
People people = session.get(People.class, 8);
Set<Car> setCar = people.getSetCar();
Car car = new Car();
car.setCname("car3");
car.setCage("2222");
setCar.add(car);
/*
* 在session中查询出来的对象都是持久态的对象,会创建对象的副本也就是快照
* 当执行transaction.commit时,堆内存数据和快照比较,若不同则执行update的方法。
*/
//session.update(people);
transaction.commit();
}catch (Exception e) {
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
/*
*select
*/
@Test
public void testSelect1() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
People people = session.get(People.class, 8);
/*
* 当调用session.get()方法时,hibernate 会立即发送请求到数据库查询。
*/
Set<Car> cars = people.getSetCar();
Iterator<Car> iterator = cars.iterator();
while (iterator.hasNext()) {
Car car = iterator.next();
System.out.println(car.getCname() +"==" +car.getCage());
}
transaction.commit();
}catch (Exception e) {
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
@Test
public void testSelect2() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
People people = session.load(People.class, 8);
/*
* 当调用session.load()方法时,hibernate不会立即发送请求,而是等用到该对象的数据源时区数据库中查询
* 也就是hibernate的懒加载机制。
*/
Set<Car> cars = people.getSetCar();
Iterator<Car> iterator = cars.iterator();
while (iterator.hasNext()) {
Car car = iterator.next();
System.out.println(car.getCname() +"==" +car.getCage());
}
transaction.commit();
}catch (Exception e) {
transaction.rollback();
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
/*
* hql查询
*/
@Test
public void testhql() {
try {
sessionFactory = HibnernateUtil.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
String hql="FROM People";
Query<People> createQuery = session.createQuery(hql, People.class);
List<People> list = createQuery.list();
System.out.println(list.get(0).toString());
transaction.commit();
}catch (Exception e) {
e.printStackTrace();
}finally {
session.close();
sessionFactory.close();
}
}
}
对以上代码有以下几点说明,
1.对添加people的操作,我们可以直接添加上people以及所属的car。这样就是有两种实现方式,第一种就是双方都维护关系,即:people的set设置上car,car中的people设置上所属的people。session要同时保存car和people对象。第二种就是一方维护关系,需要在的少的一方配置<set name="setCar" cascade="save-update,delete">,表示少的一方维护关系。这样话,就只需要people的set设置上car集合,保存的时候只保存people对象即可。
2.在add操作时,我们可以看出hibernate运行时序,首先是对两个类对象保存在硬盘上,然后更新,将car的外键指people的主键,这对初学者了解即可。
3.关于session.get()与session.load()方式查询说明。
session.get()方式查询,hibernate会立刻向数据库发送请求,获取数据。
session.load()方式查询,hiebrnate不会立刻向数据库发送请求,而是等到程序需要使用数据中查出的对象时,hibernate才会向数据库发送查询请求。
两者之间请求时间差问题,体现了文件hibernate的优化。
4.hibenate中对象的三种状态:即:持久态(persistent),游离态(detached),瞬时态(transient)
持久态:一般只session.get()和session.load()方式获取到的对象。
瞬时态:session.add()方法之前,对象都是瞬时态。
游离态:session.update()和session.delete()方法调用之后,事务提交之前,属于游离态。
5.hibernate一级缓存
hibernate一级缓存是基于session 对象的,默认是开启状态,它的生命周期就是session的声明周期。session查询对象时,向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,会清理Session的一级缓存,将一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将一级缓存的对象同步到数据库,并更新快照;如果一致,则不执行update语句。
6.解释了4和5两条内容,终于到了重点了。那么我们现在来解释一下session.update()方法的 ,我们在更新之前,一定会调用查询方法,得到结果对象,此时对象是持久态的对象。在缓存区和快照区均有此对象。所以当我们改变对象的属性后,不使用session.update()方法直接提交事务,也会实现update的功能。
7.调用session.delete()方法时,我们可以看出是将两者之间的关系先解除后分别删除。session删除的时候是根据id删除的,所以即使我们的对象不是持久态的对象,一样可以实现删除。
G:源码下载地址:hibernate多对一demo下载
今天呢,小编就先讲解到这里。后续小编会继续写hibernate的其他内容。