您的位置:首页 > 数据库

Hibernate 学习笔记(1):入门

2016-03-24 15:10 513 查看
Hibernate虽说比较好用,但是内容也是太多了,之前看到别人拿他和mybatis相比,确实从结构上来说,mybatis确实比较简单,上手也比较容易,但是没有hibernate自动化程度高,再加上之前接手的项目都是用这个框架写的,所以自然而然。。

一、 认识Hibernate

Hibernate是一个ORM框架,对于ORM应该每个人都很熟了,就不赘述了。之前hibernate是一个包的,但是之后根据功能分出了几个独立的包。
主要的包有如下几个:

hibernate-core:是Hibernate的核心模块,

hibernate-entitymanager:是hibernate对JPA的支持;

hibernate-c3p0:提供了hibernate对c3p0数据库连接池的支持;

hibernate-java8:对java8中新出现的数据类型的支持;

可以使用maven来配置依赖库,先导入一个最简单的依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.1.Final</version>
</dependency>

要使用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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3305/hibernatedemo</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping resource="com/hibernate/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
相信用过JDBC的人都很熟悉了,其中只有一个dialect和mapping是陌生的,dialect是说明对哪个数据库进行支持,mapping是提供要映射到数据库的实体类的配置信息。

其实关于配置mapping有两种方法,一是XML文件的方式,另一种是注解的方式。
有了上面的配置文件,要怎么加载这些配置呢?
使用hibernate自己提供的API,首先在整个应用生命周期的开始创建SessionFactory,有多种方式来完成这一工作,但是通过查看文档,典型的方式使用如下,抛弃了之前使用过的Cnfiguration:
// A SessionFactory is set up once for an application
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure()  // configures settings from hibernate.cfg.xml
.build();
SessionFactory factory;
try{
factory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
}
catch(Exception e){
StandardServiceRegistryBuilder.destroy(registry);
}
StandardServiceRegistry结合配置文件中的配置信息注册为一个服务,以便让SessionFactory使用。
MetadataSources则开始告诉Hibernate你的domain model(和持久化类不一样,但是在具体上可以理解成持久化类), Metadata则代表了所有从映射源(XML,注解)获得的ORM模型,通过它们来构建SessionFactory。
SessionFactory是线程安全的对象并且在一个应用中只会实例化一次来服务于整个应用。它用来生产Session实例,Session实例其实是具体完成每一次数据库操作的工作单元。比如完成如下操作:
Session session = factory.openSession();
Transaction transaction = session.beginTransaction();
session.save(new User(1, "lmy", "123")); // crud
transaction.commit();
session.close();
其中提供了事务支持,以上就完成了一个基本的操作。
hibernate的基本信息配置完之后,还要注意实体类的配置,需要遵守一定的规范,这里指的是JavaBean规范,并不是强制的,但是一种惯例。

所有属性设置为私有,并且提供setter和getter的方法;
要有无参的构造函数,因为hibernate会通过反射为你创建对象;

二、 Hibernate的xml配置方式

使用XML的配置方式,无非是通过XML的各种节点和属性完成信息配置,由于我用这种方法不多,所以在这里简单说一下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2015-9-29 1:47:37 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.hibernate.entity.User" table="t_User">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="username" type="java.lang.String">
<column name="USERNAME" />
</property>
<property name="password" type="java.lang.String">
<column name="PASSWORD" />
</property>
</class>
</hibernate-mapping>
基本使用如上所示,提供类的全限定名,要映射到数据库的表名,其中属性的名称,类型以及映射到的列名。

注意的是每个实体类都会有这样一个映射文件来完成配置,所以实体类一多,就会有很多的映射文件,之后还要把这些文件配置到hibernate的配置文件中,通过mapping节点中的resource属性加入,由于这样有很多麻烦,所以我们更多的是使用注解的方式来完成配置。

三、 Hibernate的注解配置方式

使用注解的配置方式,只要在对应的实体类加上对应的注解即可,不用多多余的文件。配置好实体类后要在hibernate的配置文件中加入mapping节点中的class属性标明。
如下:
<mapping class="com.hibernate.entity.User"/>
实体类如下:
package com.hibernate.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name="user")
public class User {

@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy="increment")
private Integer id;
@Column(name = "Username")
private String username;
private String password;
@Temporal(TemporalType.TIMESTAMP)
private Date date;

public User(){}

public User(Integer id, String username, String password) {
super();
this.id = id;
this.username = username;
this.password = password;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
}

}

@Entity标明这是一个实体类,有一个属性表明了该实体的名字,用于查询数据库时使用,对应于文件中的class节点
@Table注解用于标明对应到数据库中的表,name属性用于指定表名。
@Id表示这是实体类的主键。
@GeneratedValue和@GenericGenerator一般一起使用,用于说明实体类的主键以怎样的方式生成。值得注意的是@GeneratedValue是JPA的注解,@GenericGenerator是hibernate的注解,两者之间的关系如下:@GeneratedValue是JPA中的注解,其中提供了几种主键生成策略,有TABLE,SEQUENCE,IDENTITY,AUTO,其中如果没有说明使用哪种策略则会使用默认的AUTO,而这种策略要求持久化提供者来选择合适的策略,那么就用到@GenericGenerator,这个注解是说明hibernate提供的持久化策略,上述代码中使用的是increment,说明主键通过自增保持唯一性,同时hibernate还提供其他10多种生成策略用于使用。
@Column用于标明对应列的一些元信息,比如列名,以及一些约束等等。
@Temporal用于将Java中的日期类型和数据库中的类型对应起来。

另外需要注意的是在其中password没有加入任何的注解,但是也会生成对应的列,只是因为@Entity注解的存在,被这个注解表示的类队会默认生成列,虽然没有注解标识。

四、 使用JPA进行持久化

使用JPA进行持久化之前,在原来只依赖与hibernate-core的基础上要再加入hibernate-entitymanager,来对JPA进行支持。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.1.Final</version>
</dependency>
JPA是用于映射Java对象和关系型数据库表的规范,独立于任何的提供商,它的具体实现由各个持久化提供商决定,但是使用JPA来进行开发,我们就可以独立于任何的具体实现,也就是说使用了JPA,你可以用hibernate在底层,也可以使用任何实现了JPA的其他框架。
不同于Hibernate提供的hibe.cfg.xml的配置文件,JPA使用自己的配置文件persistence.xml,具体如下:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="PersistenceUnit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.hibernate.entity.User</class>
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.password" value="1992219abclmy"></property>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/hibernatedemo"></property>
<property name="hibernate.connection.username" value="root"></property>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"></property>
<property name="hbm2ddl.auto" value="update"></property>
</properties>
</persistence-unit>
</persistence>
JPA用hibernate作为底层实现,注意现在使用org.hibernate.jpa.HibernatePersistenceProvider代替之前的org.hibernate.ejb.HibernatePersistence,之前的已经被弃用了。
上述是最简单的JPA配置,并且没有加事务控制。另外在配置hibernate的属性时,一定要加上hibernate前缀,不然会出现各种问题,我在写代码的时候在hbm2ddl.auto前忘记加hibernate,导致实体类对应的表一直不能生成(好丢人)。
在该文件中可以配置多个persistence-unit,必须提供一个唯一的名称为每个持久化单元,应用当要获得EntityManagerFactory的引用时,使用这个名称来引用数据库的配置信息,通常情况下我们在每个应用中的持久化单元只需要一个EntityManagerFactory。
在使用persistence.xml文件时,要注意它的位置,在src/main/resources/META_INF,如果不在可能会出现如下的错误:
Could not find any META-INF/persistence.xml file in the classpath
获取配置信息并进行数据库操作的代码如下:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("PersistenceUnit");
EntityManager manager = factory.createEntityManager();
manager.getTransaction().begin();
manager.persist(new User("abc", "456", new Date(System.currentTimeMillis())));
manager.getTransaction().commit();
manager.close();
还有一个问题在写代码的时候也遇到了,就是在已经声明了主键的生成策略了,但是还是手动去插入主键的值就会导致如下的错误:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist:

五、 JPA和Hibernate的几点比较

通过上面的说明,可以看到JPA和Hibernate有很多的相似点,

JPA VS Hibernate
JPAHibernate
EntityManagerFactorySessionFactory
EntityManagerSession
transactiontransaction
crudcrud
既然有这么多相似点,到底选哪一个使用呢?相关文章里有一篇说的很清楚,总的来说有以下几点:

想要灵活性,就用JPA;
想要更好的功能支持,就用Hibernate;
两者之间还可以转换,Session session = entityManager.unwrap(Session.class);

相关文章:

基于按annotation的hibernate主键生成策略

Maven/Eclipse: Could not find any META-INF/persistence.xml file in the classpath

org.hibernate.PersistentObjectException: detached entity passed to persist - with JPA

Hibernate4实战 之 第一部分 Hibernate入门

JPA EntityManagerFactory Vs Hibernate’s SessionFactory
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hibernate 数据库 jpa orm