Hibernate基础配置篇

1.创建项目并加入maven依赖

<dependencies>

    <dependency>

        <groupId>org.hibernate</groupId>

        <artifactId>hibernate-core</artifactId>

        <version>5.2.10.Final</version>

    </dependency>

    

    <dependency>

        <groupId>org.hibernate</groupId>

        <artifactId>hibernate-ehcache</artifactId>

        <version>5.2.10.Final</version>

    </dependency>

    

    <dependency>

        <groupId>mysql</groupId>

        <artifactId>mysql-connector-java</artifactId>

        <version>5.1.37</version>

    </dependency>

    

    <dependency>

        <groupId>junit</groupId>

        <artifactId>junit</artifactId>

        <version>4.11</version>

    </dependency>

</dependencies>

 

<build>

    <plugins>

        <plugin>

            <groupId>org.apache.maven.plugins</groupId>

            <artifactId>maven-compiler-plugin</artifactId>

            <version>3.1</version>

            <configuration>

              <source>1.8</source>

              <target>1.8</target>

            </configuration> 

        </plugin>

    </plugins>

</build>

2.主配置文件:

主配置文件用来指定Hibernate全局参数,以及加载实体类的映射文件,习惯命名为hibernate.cfg.xml

 

全局参数可以参考Hibernate发布包中project/etc目录下的模板文件,发布包下载地址:http://hibernate.org/orm/downloads/

 

hibernate.cfg.xmlDTD约束文件在org.hibernate包下)

<?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>

        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>

        <property name="connection.url">jdbc:mysql:///hibernateDemo</property>

        <property name="connection.username">root</property>

        <property name="connection.password">root</property>

        

        <!-- 指定数据库方言 -->

        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

        <!-- 在控制台打印生成的SQL语句 -->

        <property name="show_sql">true</property>

        <!-- 对打印的SQL语句进行格式化 -->

        <property name="format_sql">true</property>

        <!-- 根据映射文件创建、修改数据库表 -->

        <property name="hbm2ddl.auto">update</property>

        

        <!-- 加载User类的映射文件 -->

        <mapping resource="com/rupeng/pojo/User.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

 

由于不同数据库支持的SQL语句在细节上有差别,Hibernate在生成SQL语句时就要参照具体的数据库细节,这称为数据库方言。虽然Hibernate能够识别底层所用数据库,但数据库会有多个版本,Hibernate默认选择的方言版本可能不是我们想要的,所以最好自己指定数据库方言

 

至于数据库连接池,HibernateSpring整合时会交给Spring管理,就不再单独配置,这样的话使用的是Hibernate内置的数据库连接池(不可在生产环境中使用)

3.映射文件

 

HibernateORM映射包含很多方面,其中一些需要在映射文件中进行配置,比如:

 

——表,表现在类名和表名相对应

 

字段——列,表现在字段名和列名相对应

 

对象——行,表现在OID和主键相对应

 

 

 

Hibernate中用来唯一标志实体对象的字段称为OID,一般使用id字段作为OIDHibernate使用OID判断两个实体对象是否对应同一行数据,

 

 

 

实体类 User.java

 

public class User {

 

    private Long id;

    private String name;

    private Date birthday;

 

    /* get/set方法 */

}

 

 

 

映射文件习惯上命名为:类名.hbm.xmlDTD约束文件在org.hibernate包下

 

User.hbm.xml

 

<?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>

    <class name="com.rupeng.pojo.User" table="T_Users">

        <id name="id" column="id">

            <generator class="native"></generator>

        </id>

        <property name="name" column="name"></property>

        <property name="birthday" column="birthday" type="date"></property>

    </class>

</hibernate-mapping>

 

 

 

 

 

<class>用来映射类和表

 

<id>用来映射OID和主键列

 

<generator>用来指定主键生成策略

 

 

 

主键生成策略

适用类型

说明

identify

intlong

使用自动递增主键生成主键值,比如MySQL

sequence

intlong

使用序列生成主键值,比如oracle

native

intlong

根据数据库自动选择identity或者sequence

uuid

String

Hibernate生成UUID主键值

increment

intlong

Hibernate生成递增主键值

assigned

Stringintlong

由开发人员自己生成主键值

 

 

 

说明:为了降低Hibernate学习成本,课程接下来的内容都不考虑assigned策略(实际影响微弱,但如果考虑就会很绕很繁琐)

 

 

 

<property>用来映射字段和列,至于字段类型和列类型,Hibernate一般都能正确判断,但对于Date类型的字段最好使用type属性指定想要的列类型,如datetimedatetime

4.核心API

 

Hibernate有两个核心类:SessionFactorySession

 

 

 

SessionFactory

 

 

 

SessionFactory用来创建Session,一个SessionFactory对象对应一个数据库,如果项目中需要访问多个数据库,就需要配置、创建多个SessionFactory

 

 

 

项目中一般把SessionFactory配置成springbean,由spring创建、管理,所以学习阶段创建SessionFactory的代码无需记忆,直接copy即可

 

 

 

StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();

SessionFactory sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

 

 

 

 

 

创建SessionFactory时会加载并解析主配置文件和映射文件,而且这个时候很多常用SQL语句已经生成,比如:

 

 

 

 

 

 

 

 

 

Session

 

 

 

Session表示和数据库的一次会话、一次连接,内部封装了java.sql.Connection

 

 

 

Session提供了save()get()update()delete()等方法,以便对实体对象进行持久化操作,session进行持久化操作需要依赖其内部的持久化上下文,也可以简单的认为session就是持久化上下文

 

 

 

示例代码:

 

public class PersistenceTest {

 

    private SessionFactory sessionFactory;

 

    @Before

    public void init() {

        StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();

        sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

    }

 

    @Test

    public void testSave() {

 

        Session session = sessionFactory.openSession();

        session.beginTransaction();

 

        User user = new User();

        user.setName("蛋蛋");

        user.setBirthday(new Date());

 

        session.save(user);

        System.out.println(user);

 

        session.getTransaction().commit();

        session.close();

}

}

 

 

 

 

学习阶段所有的持久化操作都放在事务中(虽然查询可以没有事务)。在项目中,由于事务会交给Spring管理,Spring可以根据配置正确的给持久化操作提供事务支持,所以项目中一般不需要手动编写事务代码

 

 

 

拓展:

(1):Session工作原理

要想很好的理解session的工作原理,需要熟悉下面的两张图:

 

 

 

实体对象状态 是相对于session来说的,如果session不存在或者已经关闭,实体对象状态也就没有意义。而且实体对象状态是相对于单个session来说的,一个实体对象在sessionA中的状态和在sessionB中的状态没有任何关系

 

瞬时状态 实体对象和当前session没有任何联系(session没有持有实体对象的引用)

 

托管状态 一级缓存和档案区中都包含该实体对象的引用,并且档案区中该实体对象的状态标记为MANAGED

 

被删除状态 一级缓存和档案区中都包含该实体对象的引用,并且档案区中该实体对象的状态标记为DELETED

 

一级缓存 每个session都有自己的一级缓存,存放处于托管状态或者被删除状态的entity的引用,主要是方便持久化操作时Hibernate内部查找entity。一级缓存的生命周期只和session有关,session创建时创建,session关闭时关闭,和事务没有关系。一个session在提交上一个事务后可以再开启新事务,这些事务共享同一个一级缓存

 

<1>保存操作:

session.save(entity) 执行保存操作,最终就是执行insert语句向表中插入数据

 

 

 

具体执行过程为:

 

1 立即执行对应的insert语句,并把新生成的主键值查询出来赋值给OID

 

2 entity转变为托管状态,也就是把entity放入一级缓存和档案区,并设置状态标记为MANAGED

<2>加载操作:

 

sessionget()执行加载操作

 

 

 

具体执行过程为:

 

1 先从一级缓存中查找

 

如果找到了

2 再检查其状态标记是否是DELETED

3 如果是,表示该entity已经被删除,返回null,否则返回该entity

如果没找到

2 再从数据库中查找(也没找到则返回null

3 如果找到了,把entity转变为托管状态并返回该entity

 

 

 

 

 

@Test

public void testGet() {

    Session session = sessionFactory.openSession();

    session.beginTransaction();

 

    User user = session.get(User.class, 1L);

    System.out.println(user);

 

    session.getTransaction().commit();

    session.close();

}

<3>修改操作:

修改操作对应着执行update语句根据OID修改表中其他列,但无法修改OID本身,其他字段的值无论是否为null,都会更新到数据库中

 

修改有两种方式:

1 直接修改托管状态下的entity的字段

 

Hibernate会在事务提交前检查entity和快照数据是否一致,如果不一致,就会执行update语句。事务提交后,快照数据更新为entity当前数据

 

update语句推迟到事务提交前执行的好处是可以合并多次操作,以及过滤无效操作,如多次修改同一个字段等

 

@Test

public void testUpdate() {

    Session session = sessionFactory.openSession();

    session.beginTransaction();

 

    User user = session.get(User.class, 1L);

    user.setName("abc");

 

    session.getTransaction().commit();

    session.close();

}

 

 

 

2 调用update(entity)修改瞬时状态下的实体对象,要求OID不为null

 

具体的执行过程为:

1 先把entity转变为托管状态

2 在事务提交前(总会)执行update语句(不会对比快照),事务提交后快照更新为entity当前数据

 

@Test

public void testUpdate2() {

    Session session = sessionFactory.openSession();

    session.beginTransaction();

 

    User user = new User();

    user.setId(1L);

    user.setName("abc");

 

    session.update(user);

 

    session.getTransaction().commit();

    session.close();

}

<4>删除操作:

session.delete(entity)执行删除操作,最终就是执行delete语句根据OID从表中删除数据

 

具体执行过程为:

1 (如果entity为瞬时状态,则先转变为托管状态)

2 把状态标记设置为被删除状态

3 事务提交前执行delete语句,事务提交后,一级缓存和档案区中有关数据也会被删除,此时entity转变成瞬时状态

 

对于被删除状态的entity,逻辑上已经不存在了,之前所做的其他操作就变成了无效操作,之后则不能再执行update等持久化操作(但普通操作如访问entity的字段和方法是可以的)

 

@Test

public void testDelete() {

    Session session = sessionFactory.openSession();

    session.beginTransaction();

 

    // User user = session.get(User.class, 1L);

    User user = new User();

    user.setId(1L);

 

    session.delete(user);

 

    session.getTransaction().commit();

    session.close();

}

延迟加载:

Sessionget()第一次执行时会立即从数据库中查询数据,而load()第一次执行时则会返回一个只有OID的代理对象,查询动作会推迟到第一次调用代理对象的方法时才真正进行,这称为延迟加载(注意:调用代理对象的hashCode()eqauls()时并不会触发查询动作)

 

@Test

public void testLoad() {

    Session session = sessionFactory.openSession();

    session.beginTransaction();

 

    User user = session.load(User.class, 1L);

    System.out.println("--------------------------");

    System.out.println(user.toString());

 

    session.getTransaction().commit();

    session.close();

}

 

特别的,当load()查询不到数据时会抛出ObjectNotFoundException异常

特别的,当session关闭后再触发查询动作时会抛出LazyInitializationException异常

 

因为load()牵涉到代理对象、延迟加载等,具体执行细节就相对复杂一些,但前面所讲的一级缓存以及档案区仍然是有效的,Hibernate会正确处理好各种持久化操作

 

延迟加载属于数据库访问优化技术,单看load()好像优化效果并不明显,其实其效果主要体现在关联对象的加载上面

 

 

 

转载于:https://www.cnblogs.com/traveller-hzq/p/9744709.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值