Hibernate框架

1.Hibernate的概述

1.1 Hibernate框架的作用  

Hibernate框架是一个数据访问框架(也叫持久层框架,可将实体对象变成持久对象,详见第5章)。通过Hibernate框架可以对数据库进行增删改查操作,为业务层构建一个持久层。可以使用它替代以前的JDBC访问数据。

1.2 Hibernate访问数据库的优点

1) 简单,可以简化数据库操作代码。

2) Hibernate可以自动生成SQL,可以将ResultSet中的记录和实体类自动的映射(转化)。

3)Hibernate不和数据库关联,是一种通用的数据库框架(支持30多种数据库),可以方便数据库移植。任何数据库都可以执行它的API。因为Hibernate的API中是不涉及SQL语句的,它会根据Hibernate的配置文件,自动生成相应数据库的SQL语句

1.3 JDBC访问数据库的缺点

1)需要编写大量的复杂的SQL语句、表字段多时SQL也繁琐、设置各个问号值。

2)需要编写实体对象和记录之间的代码,较为繁琐。

3)数据库移植时需要修改大量的SQL语句。

1.4 Hibernate的设计思想

Hibernate是基于ORM(Object Relation Mapping)思想设计的,称为对象关系映射。负责Java对象和数据库表数据之间的映射。

Hibernate是一款主流的ORM工具,还有其他很多ORM工具,如:MyBatis(以前叫iBatis)、JPA。Hibernate功能比MyBatis强大些,属于全自动类型,MyBatis属于半自动。但全自动会有些不可控因素,因此有些公司会用MyBatis。

ORM工具在完成Java对象和数据库之间的映射后: HQL

1)在查询时,直接利用工具取出“对象”(不论是查询一条记录还是多条记录,取出的都是一个个对象,我们不用再去转化实体了)。

2)在增删改操作时,直接利用工具将“对象”更新到数据库表中(我们不用再去把对象转成数据了)。

3)中间的SQL+JDBC细节,都被封装在了工具底层,不需要程序员参与。

u 注意事项:

v Java程序想访问数据库,只能通过JDBC的方式,而Hibernate框架也就是基于ORM思想对JDBC的封装。

v Hibernate是以“对象”为单位进行数据库的操作。

2.Hibernate的基本使用

2.1 Hibernate的主要结构

1)hibernate.cfg.xml(仅1个):Hibernate的主配置文件,主要定义数据连接参数和框架设置参数。

u 注意事项:就是个xml文件,只是名字比较奇葩!

2)Entity实体类(n个,一个表一个):主要用于封装数据库数据。

3)hbm.xml映射文件(n个):主要描述实体类和数据表之间的映射信息。描述表与类,字段与属性的对应关系。

u 注意事项:hbm.xml是个后缀,如:命名可写Cost.hbm.xml。

2.2 Hibernate主要的API

1)Configuration:用于加载hibernate.cfg.xml配置信息。用于创建SessionFactory。

2)SessionFactory:存储了hbm.xml中描述的信息,内置了一些预编译的SQL,可以创建Session对象。

3)Session:负责对数据表执行增删改查操作。表示Java程序与数据库的一次连接会话,是对以前的Connection对象的封装。和JSP中的session不是一回事,就是名字一样而已。

4)Query:负责对数据表执行特殊查询操作+增删改。

5)Transaction:负责Hibernate操作的事务管理。默认情况下Hibernate事务关闭了自动提交功能,需要显式的追加事务管理(如调用Transaction对象中的commit();提交事务)!

u 注意事项:

v 这些API都是在Hibernate包下的,导包别导错!

v 第一次访问数据库比较慢,比较耗资源,因为加载的信息多。

2.3 Hibernate使用步骤

step1:建立数据库表。

step2:建立Java工程(Web工程也可),引入Hibernate开发包和数据库驱动包。必须引入的包:hibernate3.jar、cglib.jar、dom4j.jar、commons-collections.jar、commons-logging.jar…等,下载地址:http://hibernate.org/orm/downloads/

step3:添加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">

<!-- Generated by MyEclipse Hibernate Tools.                   -->

<hibernate-configuration>

<session-factory>

    <!-- 指定方言,决定Hibernate生成哪种SQL -->

<property name="dialect">

org.hibernate.dialect.MySQLDialect

</property>

<property name="connection.url">

jdbc:mysql://localhost:3306/hibdata

</property>

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

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

<property name="connection.driver_class">

com.mysql.jdbc.Driver

</property>

<property name="myeclipse.connection.profile">mysql</property>

 

<!-- 框架参数,将hibernate底层执行的SQL语句从控制台显示 -->

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

<!-- 格式化显示的SQL -->

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

<!-- 指定映射描述文件 -->

        <mapping resource="com/hxh/pojo/News.hbm.xml" />

</session-factory>

 

</hibernate-configuration>
 

 

Hibernate框架

 

 

 

注意事项:应该放在源文件的src目录下,默认为hibernate.cfg.xml。文件内容是Hibernate工作时必须用到的基础信息。

step4:编写Entity实体类(也叫POJO类),例如:新闻实体类News

private Integer nid;

private String title;

private String content;

private String photo;

private Integer ntid;……getter/setter方法

 

注意事项:POJO类表示普通类(Plain Ordinary Old Object),没有格式的类,只有属性和对应的getter/setter方法,而没有任何业务逻辑方法的类。这种类最多再加入equals()、hashCode()、toString()等重写父类Object的方法。不承担任何实现业务逻辑的责任。

step5:编写hbm.xml映射(文件)描述信息:映射文件用于指明POJO类和表之间的映射关系(xx属性对应xx字段),一个类对应一个映射文件。例如:News.hbm.xml内容如下:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!-- 定义COST_CHANG表和Cost类型之间的映射信息   -->

<hibernate-mapping><!-- <hibernate-mapping package="包名写这也行"> -->

<!-- name:包名.类名,指定是哪个类;table:数据库中哪个表;catalog:对Oracle而言为哪个数据库,对MySQl而言为某个用户(MySQl是在用户下建表,Oracle是在库中建表),

不写也行(若用工具则会自动生成)。例如,select * from news_chang则会在hibernate.cfg配置文件中定义的库(或用户)下去找表。若写了则为select * from system.news_chang  -->

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

<!-- 此处表示的是进行POJO类与数据表之间的映射 -->

<hibernate-mapping>

<!-- 配置的是类的相关定义,name表示类的名字,同时设置table对应的数据表,catalog表示的是数据库的名字 -->

<class name="com.offcn.pojo.News" table="news" catalog="hibdata">

<!-- 配置主键,name表示的是类之中的属性名称,type表示的是News类的nid类型 -->

<id name="nid" type="java.lang.Integer">

<!-- News类中的nid属性与数据表之中对应的列,列名称是nid -->

<column name="nid" />

<!-- 主键的生成方式,本次使用的是数据表数据的自增长 -->

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

</id>

<!-- 配置类之中的其它普通属性信息,name表示的是News类中的属性名称 -->

<property name="title" type="java.lang.String">

<!-- 定义类中的属性与表之中的映射字段 -->

<column name="title" length="50" not-null="true" />

</property>

<property name="content" type="java.lang.String">

<column name="content" length="65535" />

</property>

<property name="photo" type="java.lang.String">

<column name="photo" length="200" />

</property>

<property name="ntid" type="java.lang.Integer">

<column name="ntid" />

</property>

</class>

</hibernate-mapping>

 

 

注意事项:

 映射文件默认与POJO类放在一起;命名规则为:类名.hbm.xml。

   hbm.xml中已写出的属性与字段的映射要一一对应,若表中没有某个字段,却写了映射关系,则报错:找不到实体类。

step6:利用Hibernate API实现DAO

1)新建HibernateUtil类,用于封装创建Session的方法。如下:每个用户会对应一个Session,但是SessionFactory是共享的。

public class HibernateUtil {

private static SessionFactory sf;

static{//不用每次都加载配置信息,所以放static块中,否则每次都加载会耗费资源

Configuration conf=new Configuration();//加载主配置hibernate.cfg.xml

conf.configure("/hibernate.cfg.xml");

sf=conf.buildSessionFactory();//获取SessionFactory }

public static Session getSession(){//获取Session

Session session =sf.openSession(); return session; }     }

 

2)新建NewsDao接口

package com.hxh.dao;

 

import java.util.List;

 

import com.hxh.pojo.News;

 

public interface NewsDao {

public News findById(int id);

public void save(News news);

public void delete(int id);

public void update(News news);

  public List<News> findAll();

 

}

 

 

 

3)新建NewsDaoImpl类,用于实现NewsDao接口

package com.hxh.dao;

 

import java.util.List;

 

import org.hibernate.Query;

import org.hibernate.Session;

import org.hibernate.Transaction;

 

import com.hxh.pojo.News;

import com.hxh.utils.HibernateUtil;

 

public class NewsDaoImpl implements NewsDao {

    private Session session;

public NewsDaoImpl(){

session=HibernateUtil.getSession();

}

 

 

/*

 * @see com.offcn.dao.NewsDao#findById(int)

 * /** get方法执行查询,按主键当条件查询,如何判断是主键,是根据写的描述文件来定,

 * get方法就是findById,就是按主键去查,需指定:操作哪个类和id(主键)条件值即可,其他条件查询做不了

 */

@Override

public News findById(int id) {

// TODO Auto-generated method stub

News news=(News) session.get(News.class, id);

session.close();

return news;

}

 

/** save方法执行增加操作,注意1:获取事务并开启,增删改要注意,查询可以不管事务,因为没对数据库进行修改;注意2:主键值根据hbm.xml中的<generator>定义生成,执行后,会先获取序列值,再去做insert操作。

即先:select COST_SEQ_CHANG.nextval from dual; 然后:insert into ……  */

@Override

public void save(News news) {

// TODO Auto-generated method stub

News vo = new News() ;

vo.setTitle("今天是周五啦,高兴不?");

vo.setPhoto("nophoto.jpg");

vo.setContent("据说今天有中到大雨,小心被淹死哦,哈哈哈,可以免费游泳!");

// 6、打开事务

Transaction tran = session.beginTransaction() ;

// 7、执行更新

session.save(vo);

// 8、提交事务

tran.commit();

// 9、关闭连接

session.close() ;

}

 

/** delete方法执行删除操作,由于Hibernate以“对象”为单位进行数据库操作,

 * 所以这里要传进去一个对象,虽然是个对象,但还是按主键做条件删除,只要把主键值设置上就行,其他非主键值不用管。也可先通过id查再删 */

@Override

public void delete(int id) {

// TODO Auto-generated method stub

   Transaction tx=session.beginTransaction();

   News news=new News();

   news.setContent("ijikij即可立即");

       session.delete(news);

       tx.commit();

       session.close();

}

 

/*

 * @see com.offcn.dao.NewsDao#update(com.offcn.pojo.News)

 */

@Override

public void update(News news) {

// TODO Auto-generated method stub

session=HibernateUtil.getSession();

Transaction tx=session.beginTransaction();

session.update(news);//将cost对象更新到数据库

tx.commit();

session.close();

 

}

 

/*

 * ** 特殊查询,SQL语句:String sql="select * from COST_CHANG";

       HQL语句:String hql="from Cost"; (Hibernate Query Language)是面向对象的查询语句。

       from后写映射的类名,它是Hibernate中特有的查询语句,根据映射的类去查询。 */

@Override

public List<News> findAll() {

session=HibernateUtil.getSession();

String hql="from News";//HQL语句

Query query=session.createQuery(hql);

List<News> list=query.list();//执行查询,返回List集合

session.close();

return list;

}

 

}

 

4)新建TestCostDAO类,使用junit测试

 

package hxh.offcn.test;

 

import java.sql.Date;

import java.util.List;

 

import org.junit.Test;

 

import com.hxh.dao.NewsDao;

import com.hxh.dao.NewsDaoImpl;

import com.hxh.pojo.News;

 

public class TestDao {

@Test

public void testFindById(){//当get方法没有记录时,返回null

NewsDao NewsDao = new NewsDaoImpl();

News News = NewsDao.findById(1);

System.out.println(News);

}

@Test

public void testSave(){//id主键列由Hibernate管理,这里不用设置

News vo = new News() ;

vo.setTitle("w今天是周五啦,高兴不?");

vo.setPhoto("nophoto.jpg");

vo.setContent("据说今天有中到大雨,小心被淹死哦,哈哈哈,可以免费游泳!");

NewsDao NewsDao = new NewsDaoImpl();

NewsDao.save(vo);

  }

@Test

public void testUpdate(){

NewsDao NewsDAO=new NewsDaoImpl();

/** 注意事项:更新部分字段,不能和实现类中的删除那样,做一个对象出来!否则没设置的字段将被改为空! 即不能:News News=new News();  News.setId(90);  

   News.setStatus("1");   News.setStartTime(new Date(System.currentTimeMillis()));   */

News news=NewsDAO.findById(1);//只能先通过id找到带有所有值的对象

news.setContent("我跟发新股够了");

NewsDAO.update(news);

}

@Test

public void testDelete(){

NewsDao NewsDAO=new NewsDaoImpl();  

NewsDAO.delete(1);

}

@Test

public void testFindAll(){

NewsDao NewsDAO=new NewsDaoImpl();

List<News> list=NewsDAO.findAll();

for(News c:list){

System.out.println(c);

}

}

 

}

 

3.关联映射

3.1一对多关系one-to-many

step1:新建项目,导入Hibernate开发包,借用学生班级实体:Student和Grade,配置hibernate.cfg.xml和两个实体的hbm.xml映射文件。

step2:一个年级对应多个学生,所以为一对多关系。因此为One方Grade实体类添加Set集合属性,以及对应的get/set方法。

    //追加属性,用于存储相关联的学生信息

private Set<Student> students = new HashSet<Student>();

 

step3:在One方Grade.hbm.xml映射文件中,加入Set节点的映射

简单说明:

 <set name="属性名">

<!-- 关联条件,column写外键字段,会默认的与其表的主键相关联 -->

<key column="指定关联条件的外键字段"></key>

<!-- 指定采用一对多关系,class指定关联的类型 -->

<one-to-many class="要关联的另一方(N方)"/>

</set>

 

具体实现:

<!-- 描述services属性,采用一对多关系加载service记录 -->

<!-- 是list集合用<list name=""></list>  set集合用<set name=""></set>  -->

<set name="students" cascade="all" lazy="false">

      <key column="gid"/>        

      <one-to-many class="com.hxh.pojo.Student"/>

</set>

 

step4:借用5.17节4)中的step1中的HibernateUtil类

step5:新建TestOneToMany.java类用于测试

/**

 * 功能1:查询一个班级的所有学生信息

 */

@Test

public  void findById(){

Session session = HibernateUtil.getSessionFactory().openSession();

Grade g = (Grade)session.get(Grade.class, 1);

System.out.println(g.getGid()+" "+ g.getGname()+" "+ g.getGdesc());

Set <Student>students =g.getStudents();

for(Student stu:students){

System.out.println(stu.getSid()+" "+stu.getSname()+" "+stu.getSex());

}

session.close();

}

/**

 * 功能2:一名新生加入到一个现有的班中

 */

@Test

public  void update() {

Student stu = new Student();

stu.setSid(3);

stu.setSname("李婷3");

stu.setSex("女");

 

Session session = HibernateUtil.getSessionFactory().openSession();

Transaction tr = session.beginTransaction();

 

Grade g = (Grade)session.get(Grade.class, 1);

 

/*Set studentset=g.getStudents();

System.out.println(studentset);*/

g.getStudents().add(stu);

 

session.save(g);

session.save(stu);

 

tr.commit();

session.close();

}

 

/**

 * 功能3:删除现有班级中一名学生

 */

@Test

public  void deleteStudent(){

Session session = HibernateUtil.getSessionFactory().openSession();

Transaction tr = session.beginTransaction();

 

Grade g = (Grade)session.get(Grade.class, 1);

Student stu = (Student)session.get(Student.class, 1);

    

g.getStudents().remove(stu);

 

session.update(g);

session.update(stu);

tr.commit();

session.close();

}

/**

 * 功能4:查询一个学生的班级信息

 */

@Test

public  void findById2(){

Session session = HibernateUtil.getSessionFactory().openSession();

Student stu = (Student)session.load(Student.class, 1);

System.out.println(stu.getSid() + " " + stu.getSname());

Grade grade = stu.getGrade();

System.out.println(grade.getGname());

System.out.println(grade.getGdesc());

session.close();

}

 

/**

 * 功能5:一名现有学生转入到另一个现有班级中

 */

@Test

public  void update2() {

 

Session session = HibernateUtil.getSessionFactory().openSession();

Transaction tr = session.beginTransaction();

 

Grade g = (Grade)session.get(Grade.class, 2);

Student stu = (Student)session.get(Student.class, 3);

    

g.getStudents().add(stu);

 

session.update(g);

//session.update(stu);

 

tr.commit();

session.close();

}

 

}

 

6.2一对一关系one-to-one

step1:新建项目,导入Hibernate开发包,借用学生和考卷两个实体:Student和Paper,配置hibernate.cfg.xml和两个实体的hbm.xml映射文件。

step2:可一个学生对应一份考卷,所以为一对一关系。因此为Student实体类添加Paper属性,以及对应的get/set方法,同时为Paper实体类添加Student属性,以及对应的get/set方法。

     //追加属性,用于存储关联的Paper信息

private Paper paper;//

Paper实体类

 

package com.hxh.pojo;

 

public class Paper {

private int pid;

private String pdesc;

private Student student;

 

public int getPid() {

return pid;

}

public void setPid(int pid) {

this.pid = pid;

}

public String getPdesc() {

return pdesc;

}

public void setPdesc(String pdesc) {

this.pdesc = pdesc;

}

public Student getStudent() {

return student;

}

public void setStudent(Student student) {

this.student = student;

}

 

}

 

 

 


step3:配置Student.hbm.xml映射文件和Paper.hbm.xml 

简单说明:

<one-to-one name="属性名" class="要关联的另一方类型Account"

column="关联条件的外键字段"/>   <!-- 指明外键字段,不写主键 -->

 

注意事项:此时没有<set name="属性名"></set>标签。

具体实现:

<one-to-one name="paper" class="com.hxh.pojo.Paper" lazy="false" cascade="all"/>

 


 

 <?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping>

    <class name="com.hxh.pojo.Paper" table="PAPER" >

        <id name="pid" type="java.lang.Integer">

            <column name="PID" />

            <generator class="assigned" />

        </id>

        <property name="pdesc" type="java.lang.String">

            <column name="PDESC" length="50" not-null="true" />

        </property>

        <many-to-one name="student" class="com.hxh.pojo.Student" unique="true" >

         <column name="sid"/>

        </many-to-one>      

    </class>

</hibernate-mapping>

 

step4:借用5.17节4)中的step1中的HibernateUtil类

step5:新建TestOne2one .java类用于测试

package com.hxh.test;

 

 

import org.hibernate.Session;

import org.hibernate.Transaction;

 

import com.hxh.pojo.Paper;

import com.hxh.pojo.Student;

import com.hxh.utils.HibernateUtil;

 

public class TestOne2one {

public static void main(String[] args) {

//save();

findById2();

}

/**

 * 功能1:新增一个学生及其学生证信息

 */

public static void save() {

Student  stu = new Student();

stu.setSid(11070130);

stu.setSname("赵飞");

stu.setSex("男");

 

Paper paper = new Paper();

paper.setPid(123456);

paper.setPdesc("北京大学学生证");

 

paper.setStudent(stu);

stu.setPaper(paper);

 

Session session = HibernateUtil.getSessionFactory().openSession();

Transaction tr = session.beginTransaction();

 

session.save(stu);

 

tr.commit();

session.close();

}

 

 

/**

 * 功能2:根据学生证查询相应学生信息 

 */

public static void findById2() {

Session session = HibernateUtil.getSessionFactory().openSession();

Paper paper= (Paper)session.get(Paper.class, 123456);

System.out.println(paper.getPdesc());

System.out.println(paper.getStudent().getSname());

session.close();

}


}
上一篇:Python+Selenium练习(二十六)- 多窗口之间切换


下一篇:Matrix (二维树状数组)