Hibernate使用

hibernate是一个全自动对象关系映射框架,值得你去使用一番.

hibernate路线图

  1. Hibernate 简介(优点和缺点)
  2. Hibernate 入门案例(基于XML的操作方式)
  3. Hibernate 配置文件详解(基于xml的方式)
  4. Hibernate 常用api介绍 (事务,回顾脏读,不可重复读(行级,读更改),幻读(表级读新增)以及数据库隔离级别.并发事务的解决悲观锁和乐观锁机制)
  5. 使用Hibernate框架完成 CRUD 操作
  6. Hibernate 的对应关系详解(使用注解的方式进行配置,摘取一对多进行代码数据示例操作)

Hibernate 简介

同样的hibernate框架是基于jdbc轻量级进行的封装在这里我们再次提到一下这个叫做ORM(面向对象进行数据结构的设计)

  1. 面向对象进行数据结构的设计和数据库表的设计有什么不同
  2. hibernate讲究的是全自动对象映射,与mybatis不同,mybatis讲究的是半自动映射
  3. 最先本质是为了解决java程序员设计对象的问题,是java的开发人员不关心数据库设计和范式定律
  4. 随着业务场景的复杂以及追求可插拔的高度自由化,当然同时也是为了以后springBoot中使用JPA做铺垫,hibernate中我们除了在初次使用的时候使用XML配置后,hibernate的级联关系操作我们采取使用注解的方式进行操作
  5. 准确的来说hibernate有的东西,mybatis也有.

Hibernate 入门案例(基于XML的操作方式)

1.构建一个新的项目(引入的jar包)

IMAGE

2.分别编写实体和对应的映射文件person.clas 和 pserson_hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Person {
private int pid;
private String pname;
private Date bir;
}
//------------映射文件
<?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="com.wwj.model.Person" table="person">
<!-- 主键的生成策略采用自增 name为对象的属性-->
<id name="pid" column="pid">
<generator class="increment"></generator>
</id>
<property name="pname" column="pname"></property>
<property name="bir" column="bir"></property>
</class>
</hibernate-mapping>

3.编写全局声明配置文件 src下 (log4j保持最先的一致)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!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="dialect">
org.hibernate.dialect.MySQLDialect</property>
<!-- 数据库驱动jar包 -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!--显示sql语句是否格式化sql语句 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!--执行DDL的方式,create: 每一次运行都会覆盖原表中的内容 update: 保留原表中的内容 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 将我们的对象和表的映射文件加载到主配置文件中 -->
<mapping resource="com/wwj/model/Person_hbm.xml" />
</session-factory>
</hibernate-configuration>

4.构建操作,对比mybatis执行流程动作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
*
* @author wwj
* 1: 读取全局配置文件
* 2: 构建 sessionFactory
* 3: 创建 session(会话)
* 4: 开启transcation
* 5: 操作数据 (CRUD)
* 6: 提交事务 transcation
* 7: 关闭 session
*
*/
public class TestHT {

public static void main(String[] args) throws ParseException {
//先处理下时间
SimpleDateFormat sf1 = new SimpleDateFormat("yyyy-MM-dd");
String format = sf1.format(new Date());
Date parse = sf1.parse(format);
// 读取配置文件,实例化 默认的寻找 名字为 hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
// 构建 session 工厂
SessionFactory sf = cfg.buildSessionFactory();
// 创建 session
Session session = sf.openSession();
// 操作数据 (insert delete update) 手动开启事务
Transaction bt = session.beginTransaction();
// 操作数据 (注意这里的面向对象操作)
Person per = new Person();
per.setPname("张三");
per.setBir(parse);
// CRUD操作
session.save(per);
// 提交事务
bt.commit();
session.close();
}
}

观察控制台的输出结果以及数据库表的结构
IMAGE


Hibernate配置文件详解

关于person映射文件以及全局文件详见代码说明


Hibernate常用api介绍

  1. 基本上大部分的框架都有一个叫做config的接口(使用xml解析填写的配置文件)
  2. xxxFactory,万物皆有工厂造出来,不会平白无故的生成(工厂模式)
  3. 工厂虽然可以有很多,工厂很庞大,庞大就耗资源,所以我们才考虑对象的生成(单例模式)

(1)事务的ACID

  1. 原子性(Atomicity) 要么买要么就不买
  2. 一致性(Consistency)有买有卖,不能空仓打粮仓
  3. 隔离性(Isolation) 大家交易同一个物品的时候(互相又看不到)但是又不应该出现价格的相互影响(信息的壁垒)
  4. 持久性(Durability) 有迹可循,有记录

(2)事务并发

多个线程访问数据库同一条数据

  1. 脏读

IMAGE

  1. 不可重复读

IMAGE

  1. 幻读

IMAGE

  1. 不可重复读发生点在一行上面,而幻读是发生在整张表上面

  2. 行级锁机制和表级锁都等同于操作上面仅且只有一个事务

补充说明:通过数据所提供的隔离级别(由低到高)

  1. ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
  2. ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
  3. ISOLATION_REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
  4. ISOLATION_SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

重点说明 (操作数据都是先查在操作)

  1. 悲观锁机制:也就是同步执行,一个一个来 查询语句加上for update
  2. 乐观锁: 使用版本号的机制
    • 大家先查,看到的版本默认为1
    • 做增加删除修改的时候在版本号上面加1 帅选条件要根据当前版本号 最后提交总有先后
    • 有一个操作一定会发生异常,通过捕获异常来进行下一步的处理

使用 Hibernate 框架完成 CRUD 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class TestHT {

public static void main(String[] args) throws ParseException {
//先处理下时间
SimpleDateFormat sf1 = new SimpleDateFormat("yyyy-MM-dd");
String format = sf1.format(new Date());
Date parse = sf1.parse(format);
// 读取配置文件,实例化 默认的寻找 名字为 hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
// 构建 session 工厂
SessionFactory sf = cfg.buildSessionFactory();
// 创建 session
Session session = sf.openSession();
// 操作数据 (insert delete update) 手动开启事务
Transaction bt = session.beginTransaction();
// 操作数据
Person per = new Person();
per.setPname("张三");
per.setBir(parse);
// CRUD操作
// --1 .增加
session.save(per);
// --2 .查询 (如果查询多个,需要用到hql语句)
Person p = (Person) session.get(Person.class, 1);
// --3. 修改需要先查
p.setPname("小李");
session.update(p);
// -- 删除
session.delete(p);
// -- 查询所有
Query createQuery = session.createQuery("from Person");
List<Person> list = createQuery.list();
for(Person pp:list) {
System.out.println(pp.getPname());
}
// 提交事务
bt.commit();
session.close();
}

Hibernate的对应关系详解 (采用注解的方式)

1.一对一双向注解

Dad类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.wwj.onetoone;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
@Entity
public class Dad {
@Id
@GeneratedValue
private int did;
private String dadName;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="sonId",unique=true)
private Son son;
public int getDid() {
return did;
}

public void setDid(int did) {
this.did = did;
}
public String getDadName() {
return dadName;
}
public void setDadName(String dadName) {
this.dadName = dadName;
}
public Son getSon() {
return son;
}
public void setSon(Son son) {
this.son = son;
}

}

Son类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.wwj.onetoone;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class Son {
@Id
@GeneratedValue
private int sid;
private String sname;

@OneToOne(mappedBy="son")
private Dad dad;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Dad getDad() {
return dad;
}
public void setDad(Dad dad) {
this.dad = dad;
}

}

2.一对多双向注解

Dad类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.wwj.onetomany;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;



@Entity
public class Dad {
@Id
@GeneratedValue
private int did;
private String dadName;

@OneToMany(cascade=CascadeType.ALL,mappedBy="dad")
private List<Son> sons;
public int getDid() {
return did;
}

public void setDid(int did) {
this.did = did;
}
public String getDadName() {
return dadName;
}
public void setDadName(String dadName) {
this.dadName = dadName;
}

public List<Son> getSons() {
return sons;
}

public void setSons(List<Son> sons) {
this.sons = sons;
}


}

Son类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.wwj.onetomany;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;

@Entity
public class Son {
@Id
@GeneratedValue
private int sid;
private String sname;

@ManyToOne
@JoinColumn(name="dadId")
private Dad dad;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Dad getDad() {
return dad;
}
public void setDad(Dad dad) {
this.dad = dad;
}

}

3.多对多双向注解

Dad类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.wwj.manytomany;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;



@Entity
public class Dad {
@Id
@GeneratedValue
private int did;
private String dadName;

@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name="dad_son",
joinColumns={@JoinColumn(name="did")},
inverseJoinColumns={@JoinColumn(name="sid")})
private List<Son> sons = new ArrayList<>();
public int getDid() {
return did;
}

public void setDid(int did) {
this.did = did;
}
public String getDadName() {
return dadName;
}
public void setDadName(String dadName) {
this.dadName = dadName;
}

public List<Son> getSons() {
return sons;
}

public void setSons(List<Son> sons) {
this.sons = sons;
}


}

son类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.wwj.manytomany;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;

@Entity
public class Son {
@Id
@GeneratedValue
private int sid;
private String sname;

@ManyToMany
@JoinTable(name="dad_son",
joinColumns={@JoinColumn(name="sid")},
inverseJoinColumns={@JoinColumn(name="did")})
private List<Dad> dads;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public List<Dad> getDads() {
return dads;
}
public void setDads(List<Dad> dads) {
this.dads = dads;
}


}