hibernate学习和介绍
1.对象关系映射O/R Mapping Obejct/Relation Mapping
(1):orm:能在对象和关系型数据库两者间进行数据转换的机制
Hibernate框架:能够实现ORM的框架
session 单线程 代表应用程序和持久化层之间的一次对话,封装了一个JDBC连接.
(2):O/R Mapping Frameworks
Hibernate
Toplink(Java对象关系可持续性体系结构,优秀的对象关系映射持久层解决方案)
Jdo(Java对象持久化的新的规范,也是一个用于存取某种数据仓库中的对象的标准化API)
Ibatis(mybatis)
JPA(JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。,而Hibernate是它的一种实现。
2.hibernate操作步骤
(1):导入jar包,idea则使用配置xml文件方式
<!-- 添加mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- 添加hibernate依赖包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.6.Final</version>
</dependency>
<!--集合工具类-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<!-- jta-java transaction api -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<!-- slf4j-api 日志管理api-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<!--注解hibernate-annotations -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/ejb3-persistence -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>1.0.2.GA</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.17.Final</version>
</dependency>
(2):建立hibernate配置文件 默认名字为: hibernate.cfg.xml
①:mysql版本
<?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>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///dept?useUnicode=true&characterEncoding=UTF-8</property><!-- 注意:这里的dept是数据库名称 -->
<property name="connection.username">root</property>
<property name="connection.password">12345</property>
<!-- JDBC connection pool (use the built-in) 连接池 -->
<property name="connection.pool_size">1</property>
<!-- 数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 格式化sql语句 -->
<property name="format_sql">true</property>
<!-- 在控制台输出sql -->
<property name="show_sql">true</property>
<!-- 策略 -->
<property name="hbm2ddl.auto">update</property>
<!--使用的是本地事务(jdbc事务 本地事务:数据库只有一个)-->
<property name="hibernate.current_session_context_class">thread</property>
<!--添加映射文件-->
<mapping class="com.test.po.Dept"/>
</session-factory>
</hibernate-configuration>
②:oracle版本
<?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>
<!-- Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<!-- 这里的orcl是数据库名称 -->
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<!-- JDBC connection pool (use the built-in) 连接池 -->
<!-- <property name="connection.pool_size">1</property> -->
<!-- SQL dialect 方言 -->
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<!-- Enable Hibernate's automatic session context management 线程 单线程 -->
<!-- 在代码中获取session有两种方式,其中一种需要添加该配置 -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<!-- 配置缓存 -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<!-- 在控制台输出sql -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<!-- 策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 注解mapping文件 -->
<!--将映射文件加入到配置文件hibernate.cfg.xml中.-->
<!-- <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml" /> -->
</session-factory>
</hibernate-configuration>
(3):创建po层
package com.hibernate.pojo;
public class Dept {
private int deptno;
private String dname;
private String loc;
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "Dept [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
}
}
(4):创建dept类的映射文件 Dept.hbm.xml
<?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 package="com.hibernate.pojo">
<class name="Dept" table="Dept" >
<id name="deptno" column="deptno" >//name对应po层里面的类,column数据库里面的字段
<generator class="native"></generator>//id让他自动生成,添加数据的时候自动加上去
</id>
<property name="dname" column="dname" />
<property name="loc" />//如果javabing里和数据库里名字一样,colume可以不配置
</class>
</hibernate-mapping>
(5):创建工具类
package com.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;//不会自动帮忙导包
public class HibernateUtil {
//静态方法帮我们创建一个session工厂
//全局静态 从一开始加载就会存在,而且不会改变,这样写是一种优化方式,只需要创建一次
//final关键字,常量不可改变
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
//这里出现问题的可能性比较大,比如配置文件出问题等
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);//这个异常叫初始化异常
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
也可以像下面这样创建:
package com.test.util;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
public class HibernateUtil {
private static SessionFactory sessionFactory;
/**
*
* @return Session
*/
public static Session getSession(){
return getSessionFactory().getCurrentSession();
}
/**
* SessionFactory是重量级的
* 最好做成单例模式
* @return SessionFactory
*/
public static SessionFactory getSessionFactory(){
//保证SessionFactory为单例
if (sessionFactory == null ||sessionFactory.isClosed()) {
sessionFactory = new Configuration().configure().buildSessionFactory();
}
return sessionFactory;
}
}
(6): 编写测试类
package com.hibernate.test;
import org.hibernate.Session;
import com.hibernate.pojo.Dept;
import com.hibernate.util.HibernateUtil;
public class HibernateTest {
public static void main(String[] args) {
Dept dept = new Dept();
dept.setDname("XX部");
dept.setLoc("一群XX");
saveDept(dept);
HibernateUtil.getSessionFactory().close();
}
private static void saveDept(Dept dept) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
// 开启事务
session.beginTransaction();
session.save(dept);
// 提交事务
session.getTransaction().commit();
}
}
3.hibernate注意事项:
(1).Hibernate.cfg.xml:hbm2ddl.auto(用的比较多是create)
a)Create 自动在数据库创建表
b)Update 根据实体类更新表结构
c)create-drop关闭SessionFactory 会把数据库创建好的表给删掉
d)validate 对数据操作之前会检查表的结构是否与配置文件是否匹配
(2):先建表后建类
4:使用注解方式实现上面的案例
pom.xml里面需要将注解部分注释
不再需要类的Dept.hbm.xml映射文件
修改类:
package com.test.po;
import javax.persistence.*;
@Entity//表示实体类 注解的是实体类 用javax哪一个
@Table(name="dep")//类名与表名不一致 用javax哪一个 dept2表名
public class Dept {
private int deptno;
private String dname;
private String loc;
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}
@Id //表示主键
@Column(name = "id")//属性名与表中主键的列名不一致 一致可以不写
@GeneratedValue(strategy = GenerationType.SEQUENCE)//主键生成策略 自动生成
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
@Column(name = "dname")//非主键 如果 属性名和列名一致 可以不写
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
}
修改hibernate配置文件的mapping
<!--添加映射文件-->
<mapping class="com.test.po.Dept"/>
5:核心开发接口介绍·
Hibernate 核心接口 三种对象状态 四种操作方法
a)Configuration
i.AnnotationConfiguration
ii.进行配置信息管理
iii.用来产生SessionFactory
iv.可以在configure方法在指定hibernate配置文件
v.只需要关注一个方法:buildSessionFactory
b)SessionFactory
i.用来产生和管理session
ii.通常情况下每个应用只需要一个SessionFactory
iii.除非要访问多个数据库的情况
iv.关注两个方法即可:openSesion getCurrentSession
Opensession每次都是新的
getCurrentSession从上下文找,如果有,用旧的,如果没有,建新的
1. 用途,界定事务边界
2. 事务提交自动close
3. 上下文配置可参见xml文件中
<property name="current_session_context_classs">thread</property>
c)Session
管理一个数据库的任务单元(简单说就是增删 改 查)
方法
a)Save()
b)Delete()
c)Update()
d)SaveOrUpdate()
save()方法很显然是执行保存操作的,如果是对一个new出来的对象进行保存,自然要使用这个方法了,数据库中没有这个对象。
update()如果是对一个已经存在的游离对象进行更新那么肯定是要使用update()方法了,数据中有这个对象。
saveOrUpdate()这个方法是更新或者插入,有主键就执行更新,如果没有主键就执行插入。
区别:对于一个从游离状态到瞬态的对象(对于一个从数据库中取出来又被删除的对象),这个对象本身是有主键的,但是因为被删除了,所以这个时候因为数据库中已经没有了这条记录了。不过它还有主键存在,所以这个时候不可以使用update()或者是saveOrUpdate(),因为update()方法是认为数据库中肯定有这条记录的,而saveOrUpdate的执行过程就是先查看这个对象是不是有主键,有主键那么就执行update()方法,没有主键就执行save()方法,因此结果跟调用了update()方法的效果是一样的,结果就会出错,因为这个对象已经被删除了,数据库中已经没有这条记录了,只是它还有主键而已(仅仅是存在于内存中),因此这个时候要执行的是save()方法
e)Load
f)Get
Get与load的区别(面试重点,原理)
1. 不存在对应记录时表现不一样
2. load返回的是代理对象,等到真正用到对象的内容时才发出sql语句
3. get直接从数据库加载,不会延迟
get方法首先查询session缓存,没有的话直接发送sql查询数据库,一定要获取到真实的数据,否则返回null,并不适用二级缓存;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,就抛异常(所谓延迟加载也称为懒加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。)
(代理实际就是空的对象 并没有去数据库查询得到的 我们叫代理对象,如果 去数据库查询了 返回到了这个对象 我们叫实体对象 就是这个对象真实存在)
g)Clear方法
无论是load还是get 都会首先查找缓存(一级缓存),如果没有,才会从数据库查找,调用clear()方法可以强制清除session缓存
Session.Commit() 这个方法它自动调用了close()和flush()方法
h) 调用flush()可以强制从内存到数据库的同步
三种对象状态图
i)三种状态的区别
区分方法: 有没有id, 数据库中有没有,session缓存中有没有
Trasient(临时状态): 没有id, 数据库中没有, 缓存没有
Persistent(持久化状态):有id, 数据库有, 缓存有
Detached(游离状态): 有id, 数据库有, 缓存没有
Configuration configuration=new AnnotationConfiguration();
Configuration configuration2=configuration.configure();
SessionFactory sFactory=configuration2.buildSessionFactory();
Session session=sFactory.getCurrentSession();
session.beginTransaction();
//临时状态
//此时的people为一个Transient对象,因为没有与任何数据库的任何记录相关联.
People people=new People();
people.setName("女娲");
people.setSex(Gender.male);
//持久状态 缓存区中有记录 数据库中也有记录
session.save(people);
session.getTransaction().commit();
//游离状态 缓存无(session关闭了无人管理了所以称为游离):
System.out.println(people.getId());
save方法完成之后,session将对象引用放在session缓存区中,
有一个hasMap引用,里面有一系列key和对应的vaule指向这个应用的对象。
比如上面的save(t)完成之后,会 有一个id的key,然后value指向数据库中那个对象。