hibernate_入门

下载地址是:http://hibernate.org/orm/

本例使用hibernate-4.3.8

    Hibernate的底层依然是基于jdbc,因此在应用程序中使用Hibernate执行持久化是同样少不了jdbc的驱动。以下采用的数据库是Mysql6.0,也就是说我们在开发项目的时候需要导入相应的数据库的驱动包。

    由于hibernate与JPA的关系非常密切,Hibernate4.3遵守最新的JPA2.1规范,一次Hibernate基本上直接使用JPA2.1的标准注解,所以需要在项目中导入hibernate-jpa-2.1.jar。在下载的hibernate文件中的lib/required即可找到这个jar包。

1) 创建web项目

新建 选择Dynamic Web Project,输入项目名:hibernate2

 hibernate_入门

最后一步选上web.xml

然后在path界面中添加JUnit

 hibernate_入门

因为后面在写test类时@Test注解需要用到。

 

2) 导入包

将目录:hibernate-release-4.3.8.Final\lib\required中的所有包全复制到lib目录。

 hibernate_入门

还需要加上:

 hibernate_入门

3) 添加配置文件:

将目录:hibernate-release-4.3.8.Final\project\etc中的

Hibernate.cfg.xmllog4j.properties复制到src目录。

 hibernate_入门

配置内容如下:

<!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://localhost:3306/test</property>

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

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

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

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

</session-factory>

<!-- po类,后面才加的 -->

<mapping class="com.gary.po.User"/>

</hibernate-configuration>

配置内容为:

使用jdbc数据源、连接本地数据库,库名为test,端口为3306,用户名为root,密码为123546.

数据源有很多种,如:dbcpc3p0proxyjndi

 

4) 添加po

添加一个user类。有一个方法复制表的字段名和类型,方便在user类中写成员变量。

Navicat中创建一个查询,输入:DESC  ‘user’,结果如下:

 hibernate_入门

这样就可以复制前两列了。User类内容如下:

package com.gary.po;

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;

@Entity

@Table(name="user")

public class User implements java.io.Serializable {

    private static final long serialVersionUID = 1L;  

    private Long id;  

    private String name;  

    private double age;  

    private Date birth;  

    @Id   // 主键

    @GeneratedValue(strategy=GenerationType.IDENTITY)// 自增长

    @Column(name="ID",unique=true)  // 字段名

    public Long getId() {  

        return id;  

    }  

      

    @SuppressWarnings("unused")  

    private void setId(Long id) {  

        this.id = id;  

    }  

      

    @Column(name="NAME",length=20)  

    public String getName() {  

        return name;  

    }  

      

    public void setName(String name) {  

        this.name = name;  

    }  

      

    @Column(name="AGE")  

    public double getAge() {  

        return age;  

    }  

      

    public void setAge(double age) {  

        this.age = age;  

    }  

      

    @Temporal(TemporalType.DATE)  

    @Column(name="BIRTH_DATE")  

    public Date getBirth() {  

        return birth;  

    }  

    public void setBirth(Date birth) {  

        this.birth = birth;  

    }  

}

 

Hibernate.cfg.xml中增加配置:

<mapping class="com.gary.po.User"/>

或者使用包名,将某个包下面的所有类都放到mapping中。

<mapping package="com.gary.po"/>

 

5) 测试读取数据:

添加一个测试类:

public class TestHibernate {

@Test

public void handle(){

// 读取hibernate配置文件信息

Configuration configuration = new Configuration().configure("hibernate.cfg.xml");

StandardServiceRegistry  serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();  

//SessionFactory factory = configuration.configure().buildSessionFactory(serviceRegistry);

SessionFactory factory = configuration.buildSessionFactory();

// 创建Session(封装jdbc)--SessionImpl

Session session = factory.openSession();

 

List<User> users = session.createQuery("from User").list();

for (User u : users) {

System.out.println(u.getId() + "===" + u.getName());

}

session.close();}

}

 

运行,输出:

 hibernate_入门

和数据库中记录一样。

 

需要注意的是,如果把po中的注解修改一***掉之前的,直接写为:

//@Entity

//@Table(name="user")

@Entity(name="user")

再测试就会报错:

 hibernate_入门

此时将hql语句中的from User改为from user就又可以查出来了,但不建议这么做。

 

6) 添加、修改数据:

上面的测试代码是读取数据,如果想要添加、修改数据上面是不够的。还需要提交事务。

Transaction tx = session.beginTransaction();

User user = new User();// 临时态

    user.setName("lisi");  

    user.setAge(28);

user.setBirth(new Date());

session.save(user);// 持久态

tx.commit();

再次运行,表中多了一条记录。

持久态的内容是不会立马写到数据库中的,只有当session调用flush后才会保存到库中。事务提交的时候应该在后台也调用了flush

 

7) 删除数据

Transaction tx = session.beginTransaction();

User user = new User();// 临时态

user.setId(Long.parseLong(String.valueOf(15)));

session.delete(user);

tx.commit();

运行,成功删除了id15的记录。

如果id15的记录不存在,则删除失败,而且后面的语句也不会执行了,相当于抛异常了。

 

8) 由主键查询记录

有两种方法通过主键去查询一条记录:loadget

如果没有匹配到数据库记录,load()方法可能抛出HibernateException异常,如果在持久化注解中指定了延迟加载,则load()方法会返回一个未初始化的代理对象,这个代理对象并没有加载数据记录,直到程序调用该代理对象的某方法时,Hibernate才会去访问数据库。 如果希望在某对象中创建一个指向另一个对象的关联,又不想在从数据库中装载该对象的同事立即装载所关联的全部对象,延迟加载方法就非常有用。

get()方法会立即访问数据库,如果没有对应的记录.get()返回null.而不是一个代理对象。

Load方法使用的是延迟加载,在使用的时候才执行,在关系映射时就有意义了。后面在讲关系的时候再细说

 

9) 修改表结构

首先不建议在代码中修改表结构,在这里只做简单笔记,

(测试也没有通过,可能是因为配置选项不正确:

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

hibernate.cfg.xml配置文件中需要增加如下配置:

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

其实这个hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议set value="none"

其中值有四个选项:

create

每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。

create-drop 

每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。

update

最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。

validate

每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

    其中需要说明一点的是,如果选择update,第一次如果没有创建表,则会创建。如果po中某个字段在库中没有,则创建,如果已有了,则不会修改,就算当前po中字段对应的长度和表中字段的长度不一样,也不会修改了,即,对表结构的创建只有第一次生效。

 

10) 数据库源

数据源有很多种,如:dbcpc3p0proxyjndi

Hibernatec3p0数据源的支持是最好的。

直接运行上面的例子,查询user表。后台的输出中有如下内容:

 hibernate_入门

即,在没有配置数据源的时候,hibernate默认是使用的DriverManager来处理的。

hibernate.cfg.xml配置文件中添加数据源配置:

<!-- c3p0数据库链接,指定连接池里最大连接数 线程池-->

<property name="hibernate.c3p0.max_size">20</property>

<!-- c3p0数据库链接,指定连接池里最小连接数 -->

<property name="hibernate.c3p0.min_size">5</property>

<!-- c3p0数据库链接,指定连接池里连接超时的时长 -->

<property name="hibernate.c3p0.timeout">5000</property>

<!-- c3p0数据库链接,指定连接池里最大缓存多少个Statement对象 -->

<property name="hibernate.c3p0.max_statements">100</property>

<property name="hibernate.c3p0.idle_test_period">3000</property>

<property name="hibernate.c3p0.acquire_increment">2</property>

加上此配置后就自动加上了数据库连接池,同时也启用了c3p0数据源。

使用c3p0需要导入相关的包,在目录:hibernate-release-4.3.8.Final\lib\optional\c3p0下有三个包:

 hibernate_入门

再次运行程序,查看后台输出:

 hibernate_入门

说明启用了c3p0的数据源。同时也查出了数据。

 

注:连接池最大值建议设置为20.

那么我们为什么要用数据源呢,为什么要用连接池呢?

如果没有连接池,每个请求都会创建一个连接,而每个连接都会消耗一些内存,当用户量太大后会因为创建的连接数据过多而导致内存不够,从而荡机。

 

11) 查看hibernate源代码

将包名复制到代码里面:org.hibernate.c3p0.internal.C3P0ConnectionProvider

,然后点进去查看源码,弹出提示如下:

 hibernate_入门

然后选择使用目录:

 hibernate_入门

选择hibernate-release-4.3.8.Final\project目录。

然后hibernate中的所有源码都会被加载进来,都可以查看了。

如:

 hibernate_入门

 

12) Hibernate4.0新特性

hibernate4.0中,使用ConfigurationbuildSessionFactory会有删除线,如下:

 hibernate_入门

那是因为4.0中已不建议这么写了。而推荐使用如下方式:

Configuration configuration = new Configuration().configure("hibernate.cfg.xml");

ServiceRegistry  serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();  

SessionFactory factory = configuration.configure().buildSessionFactory(serviceRegistry);

// SessionFactory factory = configuration.buildSessionFactory();

Session session = factory.openSession();