Hibernate基础入门整理
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框架的实现细节,对于我们来说也可以更好的理解和使用,并且可以借鉴他的思想)
下面放一张图来表示对应的关系
(画图水平有限还没有鼠标,不过我已经很努力的)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
下面,让我们来配置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的其他特性,比如注解配置的,之后我也会尽量整理出相关教程
上一篇: SpringCloudAlibaba Nacos入门概述
下一篇: Hibernate集合映射