欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hibernate基础入门整理

程序员文章站 2022-06-12 19:29:59
...

    Hibernate是一种基于ORM的思想来实现与数据库交互的框架,使用这个框架来操作数据库更为方便也更符合

面向对象的对象的思想,下面整理了一些Hibernate基础入门的知识,掌握这些基础知识对深入学习Hibernate框架原理有更好的推动

    首先,Hibernate框架是基于ORM思想的,要使用这个框架首先要准备一个符合JavaBean规范的类

public class Student {
    int id;
    String name;
    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(用于作为表的主键),name

下面,我们要导入Hibernate的JAR包以及他所依赖的JAR包,对于初学者,因为还不熟悉Hibernate框架,所以推荐整套下载资源(因为不同的Hibernate版本所依赖的JAR包有严格的规范)在这里,我分享了一套资源用于供大家下载:

     百度网盘:https://pan.baidu.com/s/13mi1KTNa5bU8uKbxpiD48A     密码:3qpn

然后我们把对应的JAR包导入项目中(至于如何导入JAR包以及如何使用,在这里就不过多阐述,如果还不熟练这些操作,那看到这里的朋友就有点心急了,要把基础打牢)

我们创建好类并且导入Hibernate框架之后,下一步,我们需要创建两个xml文件,用于把我们创建的学生类映射到Hibernate框架中,在这里,我们先简单的讲一下Hibernate的工作原理,Hibernate框架是先会读取hibernate.cfg.xml这个配置文件来读取要操作数据库的策略(具体配置的内容,后面会讲到,这里大家先了解有这么一个概念),在hibernate.cfg.xml中我们会配置操作数据库相关的操作信息,以及另一个xml文件的映射(前面我们说过,我们要准备两个xml文件),而这个xml文件的名字就是XXXXX.hbm.xml,比如,我们要把我们之前创建的Student类映射到Hibernate框架,就需要在hibernate.cfg.xml中映射Student.hbm.xml文件,在Student.hbm.xml中,我们就需要配置一些类对表的关系了(可能看到这里比较绕,不过没有关系,跟着这篇教程走,过一遍之后再回来看这句话相信你可以完全理解其中的含义),简单的总结一下就是,Hibernate框架工作会先读取hibernate.cfg.xml文件hibernate.cfg.xml,而hibernate.cfg.xml文件会读取Student.hbm.xml文件,经过这两步之后,我们就实现了类对应表的连接,而具体连接的细节,是Hibernate框架已经封装好的,不需要我们操心(但是学完Hibernate框架基础后,操心一下总是好的,更深入的理解Hibernate框架的实现细节,对于我们来说也可以更好的理解和使用,并且可以借鉴他的思想)

下面放一张图来表示对应的关系

Hibernate基础入门整理(画图水平有限还没有鼠标,不过我已经很努力的)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,让我们来配置Student.hbm.xml(这个文件的位置应当与我们要映射的类在同一个包下,在这里,也就是与Student这个类在同一个包下)

<?xml version="1.0"?>
<!-- 导入约束 -->
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <!-- 在这里填写Student所在的包路径,我的Student类在cn.encore.bean这个路径下 -->
<hibernate-mapping package="cn.encore.bean">
 <!-- 这里配置主要的映射关系,我们要把Student类映射到student这个表中,name属性填类名,table属性填表名 -->
    <class name="Student" table="student">
 <!-- 把我们的学生类的id属性作为主键,<generator class="native"> 意味着id的自增长方式采用数据库的本地方式-->
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
 <!-- 把学生类中name属性做一下映射,在这里,我们只设置了name属性,而没有声明他对应表中的哪个元素,也就是table属性,这是因为只要我们保证自己编写的JavaBean属性与表中的元素名如果相同,那么我们是可以省略配置table属性的 -->
        <property name="name" />
    </class>     
</hibernate-mapping>

下面,让我们来配置一下hibernate.cfg.xml(这个文件的位置要在项目根目录的src文件夹下)

<?xml version='1.0' encoding='utf-8'?>
<!-- XML约束 -->
<!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>
        <!-- 配置数据库url -->
        <property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property>
        <!-- 数据库账户 -->
        <property name="connection.username">root</property>
        <!-- 数据库密码 -->
        <property name="connection.password">admin</property>
        <!-- SQL dialect -->
        <!-- 数据库使用的方言,这里使用了MySql方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 这句代表一个线程启动一个session -->
        <property name="current_session_context_class">thread</property>
        <!-- 这句代表在控制台输出执行的sql语句 -->
        <property name="show_sql">true</property>
        <!-- 这句代表自动更新表结构,我们之前是根本没有创建表的,当配置这条后,Hibernate会为我们自动生成表以及自动更新表 -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 映射的XXXXXX.hbm.xml文件 -->
        <mapping resource="cn/encore/bean/Student.hbm.xml" />
    </session-factory>
 
</hibernate-configuration>

配置好之后,我们就可以使用Hibernate框架了,下面我们编写一个测试类

package cn.encore.test;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.Student;
 
public class TestHibernate {
    public static void main(String[] args) {
 //先得到一个Session工厂,用于得到Session
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
 //获取一个Session对象
        Session s = sf.openSession();
 //打开事务
        s.beginTransaction();
 //创建一个学生类,并为其设置名字
        Student stu = new Student();
        stu.setName("王闪火");
 //把这个学生保存到student表中
        s.save(stu);
 //获得事务并提交
        s.getTransaction().commit();
 //关闭session以及session工厂
        s.close();
        sf.close();
    }
 
}

运行这段代码后,我们再去查看数据库,会发现在test数据库中,多了一个student表,其中有一条叫做王闪火的记录,看到这里,相信你也深有体会了,虽然配置这个框架时相对麻烦,但是在使用起来相比传统的JDBC操作数据库要容易的多,可以说是一劳永逸了

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们编写一个插入十条数据的程序,来巩固一下使用Hibernate插入数据的操作

package cn.encore.test;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.Student;
 
public class TestHibernate {
    public static void main(String[] args) {
 
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
 
        Session s = sf.openSession();
        s.beginTransaction();
 
        for (int i = 0; i <= 10; i++) {
            Student stu = new Student();
            p.setName("代号00"+i);
            s.save(stu);         
        }
 
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
 
}

可以看到,我们要使用Hibernate操作数据库,我们先要利用SessionFactory这个类来获得一个Session对象,之后,我们打开事务,创建一个要插入的类,之后调用save方法来把这条数据保存到对应的表中(这都是基于Student.hbm.xml配置文件的),最后提交事务,关闭对应的物理资源

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们来讲一下Hibernate中,对象的三种状态:

1.瞬时 指的是没有和hibernate发生任何关系,在数据库中也没有对应的记录,一旦JVM结束,这个对象也就消失了 
2.持久 指得是一个对象和hibernate发生联系,有对应的session,并且在数据库中有对应的一条记录 
3.脱管 指的是一个对象虽然在数据库中有对应的一条记录,但是它所对应的session已经关闭了 

我们先new 了一个Student();,在数据库中还没有对应的记录,这个时候Student对象的状态是瞬时的。 
通过Session的save把该对象保存在了数据库中,该对象也和Session之间产生了联系,此时状态是持久的。
最后把Session关闭了,这个对象在数据库中虽然有对应的数据,但是已经和Session失去了联系,相当于脱离了管理,状态就是脱管的

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们利用Hibernate来获取一个对象

package cn.encore.test;
  
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
  
import cn.encore.bean.Student;
  
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
        Session s = sf.openSession();
        s.beginTransaction();
        //使用Session对象的get方法,利用id来获取一个对象,我们得到的倒是Object对象,需要做一下强转
        Student stu =(Student) s.get(Student.class, 0);
        System.out.println("id=0的同学是: "+stu.getName());
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

运行这段代码,我们可以获得到id=0的对象,也就是我们之前插入的王闪火

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们利用Hibernate来删除一个对象,在删除之前我们需要先获取这个对象

package cn.encore.test;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.Student;
 
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
        Session s = sf.openSession();
        s.beginTransaction();
        //先获取要删除的对象
        Student stu =(Student) stu.get(Student.class, 2);
        //调用delete()方法进行删除
        s.delete(stu);
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
 
}

我们先获取到了id=2的对象,也就是我们之前插入的"代号000"同学,之后,我们调用Session对象的delete()方法,把这个对象作为参数传进去,我们就实现了删除操作

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们利用Hibernate来修改一个对象,和删除相同,我们在修改一个对象之前,也要先获得到这个对象

package cn.encore.test;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.Student;
 
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
 
        Session s = sf.openSession();
        s.beginTransaction();
        //获取id为6的对象
        Student stu =(Student) s.get(Student.class, 6);
        //先打印出他之前的名字
        System.out.println(p.getName());
        //修改他的名字
        p.setName("派克特");
        //调用update方法修改
        s.update(stu);
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
 
}

运行上面的代码,我们就把ID为6的元素名字修改成了派克特

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面我们利用Hibernate框架执行查询操作,Hibernate框架为我们提供了三种查询方式,下面,我们分别用代码来演示这三种查询方式

1.HQL查询,这是Hibernate自己的一套查询语言首先根据hql创建一个Query对象,然后设置参数通过Query对象的list()方法即返回查询的结果了

package cn.encore.test;
 
import java.util.List;
 
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.Student;
 
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
        Session s = sf.openSession();
        s.beginTransaction();
     
        String name = "代号";
        //编写HQL语句
        Query q =s.createQuery("from Student s where s.name like ?");
        q.setString(0, "%"+name+"%");
        //调用Querry的list方法,得到结果集
        List<Student> ss= q.list();
        for (Student stu : ss) {
            System.out.println(stu.getName());
        }
         
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
 
}

通过如上的代码,我们得到了名字中包含“代号”的同学(没有王闪火和派克特)

2.使用Criteria进行数据查询,与HQL和SQL的区别是Criteria 完全是 面向对象的方式在进行数据查询,将不再看到有sql语句的痕迹

package cn.encore.test;
  
import java.util.List;
 
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
 
import cn.encore.bean.Student;
  
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
  
        Session s = sf.openSession();
        s.beginTransaction();
 
        String name = "代号";
          
        Criteria c= s.createCriteria(Student.class);
        c.add(Restrictions.like("name", "%"+name+"%"));
        List<Student> ss = c.list();
        for (Student stu : ss) {
            System.out.println(stu.getName());
        }
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

如上代码,我们完全没有使用SQL语句,这种方法也更符合面向对象的思想,我们先使用Criteria 查询数据通过session的createCriteria创建一个Criteria 对象,Criteria.add 增加约束。 在本例中增加一个对name的模糊查询(like),调用list()方法返回查询结果的集合
3.SQL查询,Hibernate依然保留了对标准SQL语句的支持,在一些场合,比如多表联合查询,并且有分组统计函数的情况下,标准SQL语句依然是效率较高的一种选择

package cn.encore.test;
 
import java.util.List;
 
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
 
        Session s = sf.openSession();
        s.beginTransaction();
 
        String name = "代号";
         
        String sql = "select * from student s where s.name like '%"+name+"%'";
         
        Query q= s.createSQLQuery(sql);
        List<Object[]> list= q.list();
        for (Object[] os : list) {
            for (Object filed: os) {
                System.out.print(filed+"\t");
            }
            System.out.println();
        }
         
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

因为标准SQL语句有可能返回各种各样的结果,比如多表查询,分组统计结果等等。 不能保证其查询结果能够装进一个Student对象中,所以返回的集合里的每一个元素是一个对象数组。 然后再通过下标把这个对象数组中的数据取出来。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,我们讲一下Hibernate中的多对一的关系

一个班级可以对应多个学生,而多个学生又可以对应一个班级,在这里学生对班级就产生了多对一的关系

下面,我们先编写一个班级类

package cn.encore.bean;
 
public class Classes {
    int id;
    String name;
    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;
    }
}

然后,我们创建Classes.hbm.xml配置文件

<?xml version="1.0"?>
 
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.encore.bean">
    <class name="Classes" table="classes">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property name="name" />
    </class>
     
</hibernate-mapping>

最后不要忘了在hibernate.cfg.xml中把Classes.hbm.xml映射进去

<?xml version='1.0' encoding='utf-8'?>
<!-- XML约束 -->
<!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>
        <!-- 配置数据库url -->
        <property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property>
        <!-- 数据库账户 -->
        <property name="connection.username">root</property>
        <!-- 数据库密码 -->
        <property name="connection.password">admin</property>
        <!-- SQL dialect -->
        <!-- 数据库使用的方言,这里使用了MySql方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 这句代表一个线程启动一个session -->
        <property name="current_session_context_class">thread</property>
        <!-- 这句代表在控制台输出执行的sql语句 -->
        <property name="show_sql">true</property>
        <!-- 这句代表自动更新表结构,我们之前是根本没有创建表的,当配置这条后,Hibernate会为我们自动生成表以及自动更新表 -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 映射的XXXXXX.hbm.xml文件 -->
        <mapping resource="cn/encore/bean/Student.hbm.xml" />
        <mapping resource="cn/encore/bean/Classes.hbm.xml" />
    </session-factory>
 
</hibernate-configuration>

下面,为Student类增加Classes属性

public class Student {
    int id;
    String name;
    Classes classes;
    public Classes getClasses(){
        return classes;
    }
    public void setClasses(Classes classes){
        this.classes = classes;
    }
    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;
    }
}

下面,修改Student.hbm.xml文件,为其classes属性增加映射

<?xml version="1.0"?>
<!-- 导入约束 -->
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <!-- 在这里填写Student所在的包路径,我的Student类在cn.encore.bean这个路径下 -->
<hibernate-mapping package="cn.encore.bean">
 <!-- 这里配置主要的映射关系,我们要把Student类映射到student这个表中,name属性填类名,table属性填表名 -->
    <class name="Student" table="student">
 <!-- 把我们的学生类的id属性作为主键,<generator class="native"> 意味着id的自增长方式采用数据库的本地方式-->
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
 <!-- 把学生类中name属性做一下映射,在这里,我们只设置了name属性,而没有声明他对应表中的哪个元素,也就是table属性,这是因为只要我们保证自己编写的JavaBean属性与表中的元素名如果相同,那么我们是可以省略配置table属性的 -->
        <property name="name" />
        <many-to-one name="classes" class="Classes" column="cid" />
    </class>     
</hibernate-mapping>

下面,我们编写一个测试类,把王闪火放到三年二班

package cn.encore.test;
  
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.*;
 
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
  
        Session s = sf.openSession();
        s.beginTransaction();
         
        Classes c = new Classes();
        c.setName("三年二班");
        s.save(c);
         
        Student stu = (Student) s.get(Student.class, 0);
        p.setClasses(c);
        s.update(stu);
         
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

然后去看看数据库,就会发现在Student类中新增了一个classes表,并且student表中多了一条cid的元素,并且王闪火保存着三年二班对应的ID

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

如上所述,多个学生可以对应一个班级,就实现了多对一的关系,而一个班级可以对应多个学生,也实现了一对多的关系,下面,我们来实现一下一对多

先为Classes类增加一个Set集合,用来保存Student(别问我为什么使用Set集合,因为Set集合插入,删除比List效率高,并且我们也不需要通过索引来访问元素)

package cn.encore.bean;

import java.util.Set
 
public class Classes {
    int id;
    String name;
    Set<Student> students;

    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Students> students) {
        this.students = students;
    }
    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;
    }
}

然后,在Classes.hbm.xml中映射students

<?xml version="1.0"?>
 
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.encore.bean">
    <class name="Classes" table="classes">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property name="name" />
        <!-- lazy表示非延迟加载 -->
        <set name="students" lazy="false">
             <!-- not-null表示可以为空 -->
             <key column="cid" not-null="false" />
             <one-to-many class="Student" />
        </set>
    </class>
     
</hibernate-mapping>

下面通过Classes取出里面所有的Student(其实三年二班里也只有王闪火)

package cn.encore.test;
  
import java.util.Set;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import cn.encore.bean.*;
  
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
  
        Session s = sf.openSession();
        s.beginTransaction();
         
        Classes c = (Classes) s.get(Classes.class, 1);
        Set<Student> ss = c.getStudents();
        for (Student stu : ss) {
            System.out.println(stu.getName());
        }
 
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

一个学生可以有多个老师,一个老师也可以有多个学生,这里就实现了多对多的关系,实现多对多关系,必须要有一张中间表

下面,先创建老师类

package cn.encore.test;
 
import java.util.Set;
 
public class Teacher {
 
    int id;
    String name;
    Set<Student> students;
    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;
    }
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

编写Teacher.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping package="cn.encore.test">
    <class name="Teacher" table="teacher">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property name="name" />
 
        <set name="students" table="teacher_student" lazy="false">
            <key column="tid" />
            <many-to-many column="sid" class="Student" />
        </set>       
         
    </class>
     
</hibernate-mapping>

修改Student类,为其增加Teacher集合

public class Student {
    int id;
    String name;
    Classes classes;
    Set<Teacher> teachers
    public Classes getClasses(){
        return classes;
    }
    public void setClasses(Classes classes){
        this.classes = classes;
    }
    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;
    }
    public Set<Teacher> getTeachers() {
        return teachers;
    }
    public void setTeachers(Set<Teacher> teachers) {
        this.teachers = teachers;
    }

}

修改Student.hbm.xml文件

<?xml version="1.0"?>
<!-- 导入约束 -->
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 <!-- 在这里填写Student所在的包路径,我的Student类在cn.encore.bean这个路径下 -->
<hibernate-mapping package="cn.encore.bean">
 <!-- 这里配置主要的映射关系,我们要把Student类映射到student这个表中,name属性填类名,table属性填表名 -->
    <class name="Student" table="student">
 <!-- 把我们的学生类的id属性作为主键,<generator class="native"> 意味着id的自增长方式采用数据库的本地方式-->
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
 <!-- 把学生类中name属性做一下映射,在这里,我们只设置了name属性,而没有声明他对应表中的哪个元素,也就是table属性,这是因为只要我们保证自己编写的JavaBean属性与表中的元素名如果相同,那么我们是可以省略配置table属性的 -->
        <property name="name" />
        <many-to-one name="classes" class="Classes" column="cid" />
        <set name="teachers" table="student-teacher" lazy="false">
            <key column="sid" />
            <many-to-many column="tid" class="Teacher" />
        </set>
    </class>   
</hibernate-mapping>

别忘了把Teacher.hbm.xml映射到hibernate.cfg.xml中,这里就不多做阐述

创建三个学生一个老师,并把这三个学生与这位老师对应起来

package cn.encore.test;
   
import java.util.HashSet;
import java.util.Set;
  
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
  
import cn.encore.bean.*
   
public class TestHibernate {
    public static void main(String[] args) {
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
   
        Session s = sf.openSession();
        s.beginTransaction();
          
        //增加3个学生
        Set<Student> stus = new HashSet();
        Student stu1 = new Student();
        stu1.setName = "Gai";
        stus.add(stu1);
        s.save(stu1);
        Student stu1 = new Student();
        stu1.setName = "黄旭";
        stus.add(stu1);
        s.save(stu1);
        Student stu1 = new Student();
        stu1.setName = "爱福杰尼";
        stus.add(stu1);
        s.save(stu1);
          
        //增加一个老师
        Teacher t = new Teacher();
        t.setName("张明鑫");
        t.setStudents(stus)
        s.save(t);
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

下面,讲一下各类概念:

1.hibernate中的事务由s.beginTransaction();开始由s.getTransaction().commit();结束,在Mysql中,只有当表的类型是INNODB的时候,才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务.

2.hibernate中的延迟加载(lazyload)分属性延迟加载和关系延迟加载的,我们之前获得对象都是使用get方法,来获得,其实也可以使用load方法来获得,但获得对象后不会立即执行SQL操作,只有当我们访问了这个对象的属性之后,才会执行

3.关系型延迟加载:延迟加载又叫lazyload,在one-many many-many的时候都可以使用关系的延迟加载,把lazy配置成true就可以了,在执行多表操作时,他不会立即去查另一张表,只有当访问另一张表元素时,才会执行SQL操作

4.关于级联简单的说,没有配置级联的时候,删除班级,其对应的学生不会被删除。 但是如果配置了恰当的级联,那么删除班级的时候,其对应的学生都会被删除掉。级联有4种类型:all:所有操作都执行级联操作;none:所有操作都不执行级联操作;delete:删除时执行级联操作; save-update:保存和更新时执行级联操作;级联通常用在one-many和many-to-many上,几乎不用在many-one上,配置级联只需要修改cascade属性,例如:<set name="students" cascade="save-update" lazy="false">

5.hibernate默认是开启一级缓存的,一级缓存存放在session上,简单来说,就是在获取一个对象的时候,缓存中如果有,就不会去执行SQL操作,而直接在缓存中把对象拿出来,这也大大的增加了开发效率,如果缓存中没有找到,才会去执行SQL操作,然后把对象保存在缓存中

6.Hibernate的一级缓存是在Session上,二级缓存是在SessionFactory上,也就是说,开启二级缓存,可以在不同的Session上获取同一个对象,而不用去重复执行SQL操作,hibernate本身不提供二级缓存,都是使用第三方的二级缓存插件,推荐使用的是 EhCache提供的二级缓存

7.使用Criteria进行分页查询 无论你使用的是Oracle,Mysql,NoSQL还是DB2,分页查询的代码写法都是一样的:

Hibernate使用Criteria 来进行分页查询
c.setFirstResult(2); 表示从第3条数据开始
c.setMaxResults(5); 表示一共查询5条数据

8.都通过id=500去获取对象 ,get方式会返回null ,load方式会抛出异常

9.Hibernate有两种方式获得session,分别是: 
openSession和getCurrentSession 
他们的区别在于 :
       1. 获取的是否是同一个session对象 
       openSession每次都会得到一个新的Session对象 
       getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象 
       2. 事务提交的必要性 
       openSession只有在增加,删除,修改的时候需要事务,查询时不需要的 
       getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭

以上就是Hibernate框架的基础理论知识,小伙伴们在消化完这些,还可以继续深入理解Hibernate的其他特性,比如注解配置的,之后我也会尽量整理出相关教程

 

相关标签: Hibernate