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。
最后一步选上web.xml。
然后在path界面中添加JUnit:
因为后面在写test类时@Test注解需要用到。
2) 导入包
将目录:hibernate-release-4.3.8.Final\lib\required中的所有包全复制到lib目录。
还需要加上:
3) 添加配置文件:
将目录:hibernate-release-4.3.8.Final\project\etc中的
Hibernate.cfg.xml和log4j.properties复制到src目录。
配置内容如下:
<!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.
数据源有很多种,如:dbcp、c3p0、proxy、jndi
4) 添加po
添加一个user类。有一个方法复制表的字段名和类型,方便在user类中写成员变量。
在Navicat中创建一个查询,输入:DESC ‘user’,结果如下:
这样就可以复制前两列了。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();}
}
运行,输出:
和数据库中记录一样。
需要注意的是,如果把po中的注解修改一***掉之前的,直接写为:
//@Entity
//@Table(name="user")
@Entity(name="user")
再测试就会报错:
此时将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();
运行,成功删除了id为15的记录。
如果id为15的记录不存在,则删除失败,而且后面的语句也不会执行了,相当于抛异常了。
8) 由主键查询记录
有两种方法通过主键去查询一条记录:load、get。
如果没有匹配到数据库记录,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) 数据库源
数据源有很多种,如:dbcp、c3p0、proxy、jndi
Hibernate对c3p0数据源的支持是最好的。
直接运行上面的例子,查询user表。后台的输出中有如下内容:
即,在没有配置数据源的时候,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下有三个包:
再次运行程序,查看后台输出:
说明启用了c3p0的数据源。同时也查出了数据。
注:连接池最大值建议设置为20.
那么我们为什么要用数据源呢,为什么要用连接池呢?
如果没有连接池,每个请求都会创建一个连接,而每个连接都会消耗一些内存,当用户量太大后会因为创建的连接数据过多而导致内存不够,从而荡机。
11) 查看hibernate源代码
将包名复制到代码里面:org.hibernate.c3p0.internal.C3P0ConnectionProvider
,然后点进去查看源码,弹出提示如下:
然后选择使用目录:
选择hibernate-release-4.3.8.Final\project目录。
然后hibernate中的所有源码都会被加载进来,都可以查看了。
如:
12) Hibernate4.0新特性
在hibernate4.0中,使用Configuration的buildSessionFactory会有删除线,如下:
那是因为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();