Hibernate

什么是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映射文件

  1. 持久化类建议实现java.io.Serializable接口, 以支持对象序列化
  2. 属性类型使用包装类型, 如: Integer, Byte, Double等
  3.  符合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>

注意事项:

  • property表示持久化类的属性, 所以name属性必须和类的属性名一致, 区分大小写
  • column表示数据表的列, 其名称应该和对应数据表的列名一致
  • 要符合标记语言规范, 多个属性之间用空格分隔

 创建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在数据库中能找到的时候,updatemerge的执行效果都是更新数据,发出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操作。

快照不可以操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值