什么是Hibernate?
hibernate是一个专注于数据持久化的框架, 是主流的对象 - 关系映射工具
优点:
1. 对面向对象特性支持良好( Objective )
2. 可移植性好
缺点:
1. 很难处理对特定数据库的优化
2. 不适合大规模的批量数据处理
什么是持久化?
Persistence, 持久化, 指的是将java应用程序中的对象保存到数据库, 将对象属性值的更新或删除同步到数据库, 或者是把从数据库查询得到的结果集转换为对象, 简言之, 对数据库的查询, 保存, 删除, 更新操作(CRUD)都称为持久化。
什么是ORM?
ORM, Object Relationship Mapping, "对象 - 关系"映射, 指的是把对象及对象间的关系映射到数据库中的表及表间关系.
为什么需要ORM ?
java程序中偏好用对象来描述数据, 而传统的关系型数据库(如MySQL, MSSQLServer, Oracle等)偏好用表中的行(一行又包含多个列的值)来描述数据, 所以在进行应用程序开发时, 需要在这2种描述形式之间作转换, hibernate在这一方面表现非常优秀.
class(类) -> table(表)
class.property(类的属性) -> table.column(表的列)
class.oid(对象的id) -> table.pk(表的主键)
什么是OID?
OID, Object ID, 通常对应着数据表中的主键列, 受hibernate管理的对象其OID值不能重复, 否则认为是同一对象, 所以OID实际上用于唯一标识一个实体对象
此为hibernate的主键策略
Hibernate的体系结构
描述: 应用程序将需要持久化的对象交给hibernate, hibernate通过读取hibernate.cfg.xml和mapping映射文件的信息, 决定如何持久化到数据库
使用Hibernate的步骤
1. 导入Hibernate需要的jar包
2. 在根目录下(src),新建一个xml配置文件,全名为hibernate.cfg.xml,里面的配置信息如下。注意下面的项目里面引入了druid数据库连接池,配置有一些改变。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--连接数据库-->
<property name="driverClassName">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://127.0.0.1:3306/jd</property>
<property name="username">root</property>
<property name="password">root</property>
<!--druid数据库连接池-->
<property name="hibernate.connection.provider_class">
com.alibaba.druid.support.hibernate.DruidConnectionProvider
</property>
<!--sql方言,依据使用的sql版本-->
<property name="dialect">org.hibernate.dialect.MySQL57Dialect</property>
<!-- DB schema will be updated if needed -->
<!--输出sql语句-->
<property name="show_sql">true</property>
<!--格式化sql语句-->
<property name="format_sql">true</property>
<!--检查有没有对于的表,没有就自己创建-->
<property name="hbm2ddl.auto">update</property>
<!--映射文件-->
<mapping resource="mapping/User.hbm.xml"></mapping>
<mapping resource="mapping/Staff.xml"></mapping>
<mapping resource="mapping/Department.xml"></mapping>
<mapping resource="mapping/Customer.hbm.xml"></mapping>
<mapping resource="mapping/Goods.hbm.xml"></mapping>
<mapping resource="mapping/MyGoods.hbm.xml"></mapping>
<mapping resource="mapping/GoodsDetail.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
3. 编写持久化类及对应的mapping映射文件
- 持久化类建议实现java.io.Serializable接口, 以支持对象序列化
- 属性类型使用包装类型, 如: Integer, Byte, Double等
- 符合JavaBean规范, 如:
- 属性名采用驼峰命名法, 如: custNick, custSex; 但不要出现cNick, cSex等特殊命名
- 属性应该具有公有的getter和setter方法
- 必须具备公有的无参构造器(包括隐式构造器)
package com.bj169.entity;
import java.io.Serializable;
/**
* @ClassName User
* @Description TODO
* @Author Administrator
* @Date 2018/12/4 0004 14:40
* @Version 1.0
**/
public class User implements Serializable {
private Integer uid;
private String username;
private String pwd;
private String address;
public User() {
}
public User( String username, String pwd, String address) {
this.username = username;
this.pwd = pwd;
this.address = address;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", pwd='" + pwd + '\'' +
", address='" + address + '\'' +
'}';
}
}
4. 映射文件
命名为 "持久化类名.hbm.xml
<!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.bj169.entity.User" table="users">
<id name="uid" column="uid">
<!--自动增长-->
<generator class="native"></generator>
</id>
<property name="username" column="username" type="java.lang.String"></property>
<property name="pwd" column="pwd" type="java.lang.String"></property>
<property name="address" column="address" type="java.lang.String"></property>
</class>
</hibernate-mapping>
注意事项:
创建SessionFactory,将SessionFactory设计成单例模式
在hibernate设计的时候, SessionFactory对象在hibernate系统中只能有一个对象.
所在java web项目中, SessionFactory一创建,一直使用,不再关闭.将SessionFactory设计成单例模式
一般要将它包装成单例模式.
package com.bj169.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* @ClassName SessionFactoryUtils
* @Description TODO
* @Author Administrator
* @Date 2018/12/4 0004 16:45
* @Version 1.0
**/
public class SessionFactoryUtils {
//声明一个私有的静态final类型的Configuration对象
private static final Configuration config;
//声明一个私有的静态final类型的SessionFactory对象
private static final SessionFactory factory;
//通过静态代码块构建SessionFactory
static {
config = new Configuration().configure();
factory = config.buildSessionFactory();
}
//提供一个共有的静态方法供外部获取,并返回一个session对象
public static Session getSession() {
return factory.openSession();
}
}
事务的操作(包含异常处理)应该属于service的范畴,但是会通过spring管理
持久化操作靠Session来完成,以面向对象的方式操作数据库,增删改都需要事务的支持,查询不需要.
public void insertStaff(Staff s, Department d) {
Session session = SessionFactoryUtils.getSession();
Transaction transaction = session.beginTransaction();
Object o = session.createQuery("select d.depId from Department d where d.depName= ?1 ").setParameter(1, d.getDepName()).uniqueResult();
System.out.println(o);
d.setDepId((Integer) o);
s.setDepartment(d);
session.save(s);
transaction.commit();
session.close();
}
Hibernate.cfg.xml配置之hbm2ddl.auto
sql语句,分为两类:
1.dml 数据操作语言,增删改查
2.ddl 数据定义语言,新建表,新建序列,删除表,更新表……
update:将映射文件与类比较,以映射为主(常用)
create:如果表存在,删除,再创建
create-drop:create,使用完毕之后,drop
validate:将映射文件与类进行验证,如果不匹配,报错
Hibernate持久化基本API
1.OID
Object ID, 通常对应着数据表中的主键列, 受hibernate管理的对象其OID值不能重复, 否则认为是同一对象, 所以OID实际上用于唯一标识一个实体对象
此为hibernate的主键策略
OID->映射文件中对应主键的属性
<id name="uid" column="uid">
<!--自动增长-->
<generator class="native"></generator>
</id>
好处: 在session执行过程中,对象请求会先被hibernate判断,不用等到进入数据库之后判断主键是否重复,减少了数据库的IO,增强性能
2. 配置数据库连接池:druid,前面已经有代码
3. 关于事务的回滚
普通测试不需要回滚(执行完毕即释放);服务器中则不可以
回滚操作在catch中,try…catch…finally包含事务控制后要放在service里,但在ssh整合以后,事务的控制被封装并交给了spring来管理(代码中不体现)
4. 增删改操作
save( Object ) 返回 序列化对象(OID对象-id值)
delete( Object ) 只需要这个对象的id在数据库存在即可
update( Object )
id是不更新的,因为id只是唯一标识一行数据.并没有任何的业务逻辑意义.
id是不变的,根据这个id找到要更新的对象,默认所有属性都更新
缺点就是更新过多,效率相对低
5. 根据主键查询对象
get( 实体类型, 主键值 ):发出sql语句从数据库中查询实体对象
load( 实体类型, 主键值 ):使用延迟加载的方式,返回的是一个代理对象,这个对象里只保存实体对象的id值(不管这个id(主键)值在数据库中是否存在),当需要使用代理对象调用除id值的其它属性时会进行sql查询,如果代理对象的id值在数据库中不存在,会报ObjectNotFoundException异常。
6. 保存或修改
saveOrUpdate() 数据库中存在记录就执行更新操作,没有就执行save插入操作。
merge():新new一个对象,如果该对象设置了ID,则这个对象就当作游离态处理:
当ID在数据库中不能找到时,用update的话肯定会报异常,然而用merge的话,就会insert。当ID在数据库中能找到的时候,update与merge的执行效果都是更新数据,发出update语句;如果没有设置ID的话,则这个对象就当作瞬态处理:用update的话,由于没有ID,所以会报异常,merge此时则会保存数据,根据ID生产策略生成一条数据;
7. hibernate中get和load有什么区别?
返回值:
get()返回的是查询出来的实体对象,而load()查询出来的是一个目标实体的代理对象。
查询时机:
get()在调用的时候就立即发出SQL语句查询,而load()在访问非ID属性的时候才会发出查询语句并且将被代理对象target填充上,但是如果这个动作发生在Session被关闭后的话就会抛出LazyInitializationException。
查询结果为空时(有待再次求证):
get()返回null
load()抛出ObjectNotFoundException
8. 一级缓存 session中的默认存储机制
第一次要执行sql语句,第二次没有,第二次直接从缓存里
核心: session在内存中创建一级缓存(持久态对象具有缓存)
9. 快照
当上一个查询完成的时候,保存查询结果的位置,方便和一级缓存作对照
对照的依据是OID
当对查询的结果进行了set操作后,提交事务的时候会把快照和缓存进行比对,如果对象不相同就执行数据库update操作。
快照不可以操作