说起hibernate,肯定很多人一肚子苦水,也肯定很多人满口称赞,说大幅提高开发效率。
Hibernate是个让人爱又让人恨的东西。当时Hibernate的创造者的想法非常好,就是利用这个框架来屏蔽数据库的差异,做到无论是mysql、oracle、sqlserver还是其他,对开发都不影响,开发者只关注业务处理。
三种状态,临时、持久、游离
学Hibernate第一个要了解的概念就是Hibernate对象的三种状态。确实非常难以理解,我学了好多年,也是近些年才慢慢理解的。我是06年就开始学习Hibernate的,当时是2.0版本,教材是上海交大孙卫琴的精通Hibernate。记忆尤深,主要是这本书看了好多好多遍,讲的太高深苦涩了。
我说一下我对这个状态的理解:
- 临时:
Person person=new Person()
,这个person就是临时状态,跟数据库无关的,如果线程结束,对象被垃圾回收,这个对象也就不存在了。 - 持久:这个好理解,就是数据库里也有对应的记录,比如
Person person=session.load(1)
; - 游离:这个比较难理解,举个例子,比如新增person,执行完
session.save(person);
然后还没有提交数据库,这个状态就是游离状态,还没有完全持久化,不过person这个对象已经有对应的id主键了。如果继续执行session.commit();
,那这个对象就变为持久化了。
确实好难理解,说着说着我就晕了。不过没关系,真到用起来,碰到问题自然而然就理解了。
对象关联关系
对象的关联关系有1对1,1对多,多对1,多对多,还分有中间表关联,没有中间表关联等等多种情况。基本一本Hibernate的教程至少三分之一是讲这些内容。确实很高深,以纯面向对象的理念来开发数据库编程。
不过多数开发人员搞不清这些关联关系,完全对照着数据库表结构建对象。Hibernate设计之初,是先设计领域模型,然后根据领域模型的关系进行反向工程,推出数据库设计。咱们一般是不相信Hibernate的领域模型的,或者不相信自己的设计能力,更相信数据库的设计能力,都是先建表,然后倒推领域模型,最终出的结果就是四不像了。而且myeclipse工具帮了倒忙,算是Hibernate的神助攻,推出数据库的反向工具。
还有一个问题,多数项目都会遇到这个问题,为了简化开发,各个对象的关联关系都取消了,只是简单利用Hibernate 的增删改的简化方法,核心的查询反而没用到。我曾经问很多人,项目用到Hibernate了,好处在哪?仅仅一句话,不用写增删改sql了。这其实会暴露更多的问题,比如update非全字段,仅仅几个字段怎么处理?Hibernate的好处一点没用到,反而额外增加了开发难度。
Hibernate调优
这基本是所有开发人员后期面对的一个问题,Hibernate性能有问题,遇到数据量大的表,查询有问题,或复杂查询写不了,还得依赖原生sql来完成,比如group by、left join等等。所以本该数据库要做的事情,拿到程序里来写了,而且写完让人看不懂,确实难懂,因为Hibernate会根据对象映射关系生成自己的sql,全是别名,很难理解。
Hibernate的学习曲线
Hibernate的学习非常高,可以毫不夸张的讲,没几个月的时间很难深入理解。但是还有很多项目用这个,原因就是如果业务逻辑不复杂的话,可以快速开发,增删改查基本都不用写代码。我以前做过一个项目,dao层用的泛型dao,service层用的泛型service,Controller层用的泛型Controller,全基于接口编程,只要建好各个类名,一句话都不用写,整个功能就完成了,包括增删改、分页、取单条记录等等,超级牛逼啊。这不就实现了无招胜有招吗,一句代码不写,功能全部完成,而且还不可能出错。反过来讲,如果要改一个逻辑,肯定蒙圈,没代码改什么啊!
说了很多,下面还是得写个例子来讲解一下什么是Hibernate的。
pom.xml
添加依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.10.Final</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
这里版本用的比较老,我也没办法,因为Hibernate变化太快,现在都是5点几版本了,我是好几年没用,跟不上时代了,不过没关系,原理都没变。
这里强调一下,Hibernate3.6以后持久化是基于Hibernate-jpa-2.0,这个东西和WebLogic自带的有冲突,强烈建议如果选用Hibernate,一定要先在weblogic部署,看有没有问题。我有几次就是掉进坑了
hibernate.cfg.xml 连接数据库的配置
<?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>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/test</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">2</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management <property name="current_session_context_class">thread</property> -->
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<!-- <mapping resource="com/critc/model/Staff.hbm.xml" /> -->
<mapping class="com.critc.model.Staff" />
</session-factory>
</hibernate-configuration>
这里面的属性都比较好理解,稍微看下书就能明白意思。
model
@Entity
@Table(name = "staff")
public class Staff {
private int id;
private String name;//
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这里是采用注解来实现的,现在都采用注解了,配置的时代早过去了。
记住几点,必须有@ID,字段的注解尽量写在get方法上,当时讲过原因,不过写在字段上更好理解一些,也起作用。
具体操作类
public class HibernateTest {
public static void main(String[] args) {
Configuration cfg = new Configuration();
SessionFactory sessionFactory = cfg.configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
//新增
Staff staff = new Staff();
staff.setName("Hibernate");
session.save(staff);
//获取单个
Staff staff2 = (Staff) session.get(Staff.class, staff.getId());
if (staff2 != null)
System.out.println(staff2.getName());
//修改
staff2.setName("改后名字Hibernate2");
session.save(staff2);
//查询 HQL
Query q = session.createQuery("from Staff");
List<Staff> list = q.list();
for (Staff staff3 : list) {
System.out.println(staff3.getName());
}
//删除
// session.delete(staff2);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
}
上面是举个例子,简单的增删改查。
写这篇文章的目的不是教给大家Hibernate怎么用,而是说Hibernate学起来会很难,如果你有信心,有毅力,完全可以一战!