Hibernate框架

Hibernate

轻量级、持久层、ORM,Hibernate 是一款全自动的 ORM 框架。

ORM

ORM 是一种自动生成 SQL 语句的技术,它可以将对象中的数据自动存储到数据库中,也可以反过来将数据库中的数据自动提取到对象中,整个过程不需要人工干预,避免了手写 SQL 带来的麻烦

  • Object:对象
  • Relation:关系型数据库
  • Mapping:映射

Hibernate与MyBatis的比较

缓存机制

Hibernate 提供了缓存机制(一级缓存、二级缓存、查询缓存),我们可以将那些经常使用的数据存放到 Hibernate 缓存中。当 Hibernate 在查询数据时,会优先到缓存中查找,如果找到则直接使用,只有在缓存中找不到指定的数据时,Hibernate 才会到数据库中检索,因此 Hibernate 的缓存机制能够有效地降低应用程序对数据库访问的频次,提高应用程序的运行性能。

版本

  • hibernate3.x

  • hibernate4.x

  • hibernate5.x

搭建hibernate环境

  • hibernate jar放进项目
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <hibernate.version>5.4.1.Final</hibernate.version>
    <hibernate-validator.version>6.0.13.Final</hibernate-validator.version>
    <mysql.version>5.1.47</mysql.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <!--hibernate核心依赖包-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <!--数据持久化依赖-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <!--表单验证依赖-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>${hibernate-validator.version}</version>
    </dependency>
    <!--数据库连接-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <!--Junit测试依赖-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 核心配置文件hibernate.cfg.xml
<?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>
        <!--数据库URL -->
        <property name="connection.url">
            jdbc:mysql://localhost:3306/video
        </property>
        <!--数据库用户 -->
        <property name="connection.username">root</property>
        <!--数据库用户密码 -->
        <property name="connection.password">123456</property>
        <!--数据库JDBC驱动 -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <!--每个数据库都有其对应的Dialect以匹配其平台特性 -->
        <property name="dialect">
            org.hibernate.dialect.MySQL5Dialect
        </property>
        <!--在控制台打印语句-->
        <property name="show_sql">true</property>
        <!--指定当前session范围和上下文,为了使用懒加载 -->
        <property name="current_session_context_class">thread</property>
        <!--格式化sql-->
        <property name="hibernate.format_sql">true</property>
        <!--添加映射路径 -->
        <mapping resource="Admin.hbm.xml"/>
    </session-factory>

</hibernate-configuration>
  • 创建映射文件
<?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>
    <!-- name:类的全路径:-->
    <!-- table:表的名称:(可以省略的.使用类的名称作为表名.)-->
    <class name="net.biancheng.www.po.User" table="user">
        <!-- 主键-->
        <id name="id" column="id">
            <!--主键生成策略-->
            <generator class="native"></generator>
        </id>

        <!--type:三种写法-->
        <!--Java类型 :java.lang.String-->
        <!--Hibernate类型:string-->
        <!--SQL类型 :不能直接使用type属性,需要子标签<column>-->
        <!--<column name="name" sql-type="varchar(20)"/>-->
        <property name="userId" column="user_id" type="java.lang.String"/>
        <property name="userName" column="user_name"/>
        <property name="password" column="password"/>
        <property name="email" column="email"/>
    </class>
</hibernate-mapping>

关联映射

  • 一对多
  • 多对多
  • 一对一

常用主键生成策略

  • assigned

    主键由外部程序负责生成,在 save() 之前必须指定一个,Hibernate不负责维护主键生成。也就是可以每次指定主键。该方式不推荐

  • increment

    这种方式在每次插入前,需要通过“select max(主键) from 表名 ”这种方式先查询最大ID,然后通过ID+1来作为新的主键值。这种方式也不推荐,因为这样会出现线程安全问题。

  • identity

    identity由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle这类没有自增字段的则不支持。

  • sequence

    采用数据库提供的sequence机制生成主键,需要数据库支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL这种不支持sequence的数据库则不行 hibernate3可指定使用哪个序列,hibernate5 为hibernate_sequence

  • hilo

    hilo(高低位方式high low)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。可以跨数据库。

  • native

    native由hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强。如果能支持identity则使用identity,如果支持sequence则使用sequence。

  • uuid

    UUID:Universally Unique Identifier,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字,标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

级联操作

一对多

<hibernate-mapping>
    <class name="com.ishangu.model.Category" table="t_category">
        <id name="cid" column="cid">
            <generator class="native"/>
        </id>
        <property name="cname" column="cname"/>
        <!--cascade级联操作-->
        <set name="products" cascade="save-update">
            <key column="cid"/>
            <one-to-many class="com.ishangu.model.Product"/>
        </set>
    </class>
</hibernate-mapping>
<hibernate-mapping>
    <class name="com.ishangu.model.Product" table="t_product">
        <id name="pid" column="pid">
            <generator class="native"/>
        </id>
        <property name="pname" column="pname"/>
        <property name="price" column="price"/>
        <many-to-one name="category" class="com.ishangu.model.Category" column="cid"/>
    </class>
</hibernate-mapping>
  • 增加
@Test
public void oneAndMany(){
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    Category category = new Category();
    category.setCname("水果");
    Product product = new Product();
    product.setPname("苹果");
    product.setPrice(10);
    // category 和 product 产生关系
    category.getProducts().add(product);
    // product 和 category 产生关系
    product.setCategory(category);
    session.save(category);
    transaction.commit();
    session.close();
}
  • 删除
@Test
public void del(){
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    Category category = session.get(Category.class, 2);
    session.delete(category);
    transaction.commit();
    session.close();
}

多对多

普通
<hibernate-mapping>
    <class name="com.ishangu.model.Student" table="student">
        <id name="sid" column="sid">
            <generator class="native"/>
        </id>
        <property name="sname" column="sname"/>
        <!--cascade级联操作-->
        <!--inverse外键维护,只能在一的一方放弃外键维护-->
        <set name="courses" table="sc">
            <key column="sid"/>
            <many-to-many column="cid" class="com.ishangu.model.Course"/>
        </set>
    </class>
</hibernate-mapping>
<hibernate-mapping>
    <class name="com.ishangu.model.Course" table="course">
        <id name="cid" column="cid">
            <generator class="native"/>
        </id>
        <property name="cname" column="cname"/>
        <!--cascade级联操作-->
        <!--inverse外键维护,只能在一的一方放弃外键维护-->
        <set name="students" table="sc">
            <key column="cid"/>
            <many-to-many column="sid" class="com.ishangu.model.Student"/>
        </set>
    </class>
</hibernate-mapping>
  • 增加
@Test
public void add(){
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    Student s1 = new Student();
    s1.setSname("张三");

    Student s2 = new Student();
    s2.setSname("李四");

    Course c1 = new Course();
    c1.setCname("前端");

    Course c2 = new Course();
    c2.setCname("后端");

    Course c3 = new Course();
    c3.setCname("Java");
    // s1选择了c1和c2
    s1.getCourses().add(c1);
    s1.getCourses().add(c2);

    // s2选择了c1和c3
    s2.getCourses().add(c1);
    s2.getCourses().add(c3);

    // c1被s1选了
    c1.getStudents().add(s1);

    // c2被s1,s2选了
    c2.getStudents().add(s1);
    c2.getStudents().add(s2);

    // c3被s2选了
    c3.getStudents().add(s2);

    // 如果双向关联,一定要一方放弃主键维护
    session.save(s1);
    session.save(s2);
    session.save(c1);
    session.save(c2);
    session.save(c3);

    transaction.commit();
    session.close();
}
级联

外键维护

一对多

<!--inverse外键维护,只能在一的一方放弃外键维护-->
<set name="products" cascade="save-update" inverse="true">
    <key column="cid"/>
    <one-to-many class="com.ishangu.model.Product"/>
</set>
@Test
public void foreignKey(){
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    // 获取苹果
    Product product = session.get(Product.class, 1);
    //  获取衣服类别
    Category category = session.get(Category.class, 1);
    // product 和 category 关联
    product.setCategory(category);
    // category 和 product 关联
    category.getProducts().add(product);
    transaction.commit();
    session.close();
}

多对多

HQL查询

  • 查询所有数据
/**
 * 获取所有数据
 * @return
 */
@Override
public List<House> getAllHouse() {
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    List house = session.createQuery("from House").list();
    return house;
}

/**
 * 查询所有数据
 */
@Test
public void selectAllStreet(){
    HouseDao houseDao = new HouseDaoImpl();
    List<House> allHouse = houseDao.getAllHouse();
    for (House h:allHouse
        ) {
        System.out.println(h);
    }
}
  • 分页查询
@Override
public List<House> pageInfo(int pageSize, int pageNumber) {
    Session session = HibernateUtil.getSession();
    Transaction transaction = session.beginTransaction();
    Query query = session.createQuery("from House");
    query.setFirstResult(pageSize);
    query.setMaxResults(pageNumber);
    List<House> list = query.list();
    transaction.commit();
    return list;
}

HouseDao houseDao = new HouseDaoImpl();
List<House> houses = houseDao.pageInfo(1, 5);
for (House h:houses
    ) {
    System.out.println(h);
}

hibernate的DQL操作

1:创建配置对象
2:读取配置文件
3:创建session工厂
4:获取session对象
5:具体查询操作
6:关闭session
7:关闭工厂

hibernate的DML操作

1:创建配置对象
2:读取配置文件
3:创建session工厂
4:获取session对象
5:获取事务
5:具体DML
6:提交事务
7:关闭session
8:关闭工厂

hibernate默认使用占位符形式代替参数

hbm2ddl.auto 的值

update:
1:每次使用hibernate的时候会自动检查如果表不存在则会自动创建表结构
2:每次使用hibernate的时候会自动检查,如果表中的列与xml映射不符合,会自动增加表中不存在的列(并不会删除表中存在
但是xml中没有的列)
create:
每次启动hibernate都会先删除表结构,然后再次创建表后执行sql
create-drop:
1:每次使用完hibernate后都会直接把表删掉
2:注意:只有在session工厂正常关闭的情况下才会执行最后的删除表操作
validate:
用于检查mapper与数据库表是否一致,如果不一致则直接抛异常

hibernate 主键自增策略

1:native
使用数据库本地主键生成策略 mysql=auto_increment oracle = sequence

2:uuid
使用uuid作为表的主键,需要主键类型必须是String(varchar(varchar2))

3:identity
使用数据库本地主键生成策略 mysql=auto_increment ,oracle不支持

4:sequence
使用序列作为主键(如果只配置sequence 则会自动创建一个序列叫 hibernate_sequence)mysql不支持

5:increment
会先查询当前ID的最大值,然后在上面+1(与mysql的自增长没有任何的关系)

6:tableGenerator
使用序列生成器,使用一张表来模拟序列操作,会造成很多额外sql浪费。

hibernate四种状态:(根据OID区别)

1:临时状态(瞬时态)
刚刚使用new出来的对象,没有被持久化,不再session中,没有OID
2:持久态
对象已经被持久化,加入到session的缓存中,有OID
3:游离态(托管态)
对象已经被持久化,不在session的缓存中,hibernate在提交事务的时候会自动关闭session所以事务提交后对象自动
转为游离态
4:删除状态
对象由OID,并且在session的管理中,但是已经有计划删除

getCurrentSession() 与openSession的区别

openSession 是每次都打开一个全新的session
而getCurrentSession 是从当前线程中获取session,如果当前线程不存在session的话,会使用openSession创建一个session并绑定到当前线程中。使用getCurrentSession 需要在hibernate的配置文件中配置:
thread

session对象(缓存是以map的形式存在)

1:session对象包含了很多操作数据库的方法
2:session的线程是不安全的,所以session的声明周期为(在web中)一次请求request
3:session是有一级缓存的,在一次生命周期内,获得相同类型,相同OID的对象只会发送1次sql
4:session查询出来的对象,都会放到缓存中管理
5:清楚session对象的方法,clear() 清空所有对象 session.evict(user); 清除缓存指定对象

hibernate 中查询叫做HQL查询

select 后面跟着的是model类的列名,必须与model类列名一致(大小写一致)
from 后面跟着的是model类名,大小写要求一致

hibernate中get与load的区别

  • 如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException
  • Load方法可返回实体的代理类实例,而get方法永远直接返回实体类
  • load方法可以充分利用内部缓存和二级缓存中的现有数据,而get方法则仅仅在内部缓存中进行数据查找,如果没有发现符合条件的数据,将越过二级缓存,直接调用SQL完成数据读取
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值