Hibernate
1. 内容
1. Hibernate概述
2. Hibernate入门
3. Hibernate主键策略
4. HQL入门
5. Hibernate 关联关系
2. Hibernate概述
2.1. Hibernate是什么
Hibernate是一个基于ORM的持久层框架。
持久层框架:就是操作数据库的框架。(增删改查)
2.2. ORM是什么
ORM (Object Relational Mapping),对象关系映射。就是在操作数据库之前,先将实体类与数据库表的关系建立起来。通过操作实体类的对象来操作数据库。这个就是ORM。
2.3. ORM的作用是什么
ORM是一套实现基于对象操作数据库的理念。所以作用就是为了实现不用写SQL语句,通过对象操作数据库。
2.4. Hibernate的作用是什么
既然Hibernate是一个基于ORM理念实现的持久层框架。那么它的作用就是,为了实现使用对象操作数据库。
2.5. Hibernate的应用场景是什么
Hibernate实现了通过对象操作数据库。我们知道各种数据库的SQL语言和SQL标准是有差异的。Hibernate实现了各种主流数据库的方言,只有开发人员严格根据Hibernate规范编写代码。可以实现编写一套代码,兼容多种数据库。
所以在一些需要支持多种数据库的产品型项目,使用Hibernate可以减少持久层的代码的编写。
3. Hibernate入门
3.1. 配置流程图
我们可以通过框架的配置流程图,快速了解框架的基础的必须要素。
|
问题:为什么需要一个配置文件?
答:因为我们需要一个配置文件,存储Hibernate框架的框架信息。如果没有配置文件只能将这些信息写在类里面。配置信息写在类里面,编译后就不能修改了。
问题:为什么需要一个映射文件?
答:因为Hibernate号称是一个ORM框架。需要先建立实体类与表的关系后,通过实体类的对象操作数据库。所以必须要有建立关系的映射文件,建立关系。
3.2. 配置步骤
根据以上配置流程图。我们可以得出配置步骤为:
1. 导入包(已知)
2. 创建一个配置文件
3. 创建一个获得操作对象(Session)的帮助类
4. 创建表的实体类
5. 创建映射关系文件
6. 加载映射文件
7. 实体操作(插入数据)
3.3. Hibernate依赖jar说明
|
4. 入门示例
4.1. 需求
使用Hibernate框架,插入一条数据到学生表里面。
4.2. 准备:数据库脚本
CREATE TABLE `tb_student` ( `student_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '学生编号', `student_name` VARCHAR(50) NOT NULL COMMENT '学生名', `student_pwd` VARCHAR(50) NOT NULL COMMENT '密码', `student_status` INT(11) NOT NULL COMMENT '学生状态', `create_date` DATETIME NOT NULL COMMENT '创建日期', PRIMARY KEY (`student_id`) ) ENGINE=InnoDB ; |
4.3. 配置步骤
4.3.1. 第一步:创建项目导入包
将Hibernate的zip压缩包的lib\required所有jar包加入到项目,以及mysql驱动包
|
4.3.2. 第二步:创建配置文件
注意事项:只要提供XML的框架,是必须提供DTD或者Schema规则文件的。我们需要在Eclipse配置XML的规则文件,让开发工具可以生产XML的头信息,以及对XML有提示。
Hibernate的规则文件DTD在Hibernate的核心包里面。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "hibernate-configuration-3.0.dtd" > <hibernate-configuration> <!-- 指定会话工厂的配置信息 --> <session-factory> <!-- 指定连接四要素 理念:任何框架的设置的参数名,都可以在框架里面找到对应的代码!!!!! Environment:环境变量,Hibernate的参数声明都在这里。 --> <property name="hibernate.connection.driver_class" >com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate-sms</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- 指定显示SQL --> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <!-- 指定加载的映射文件 --> <mapping resource="org/chu/pojo/hbm/Student.hbm.xml"/> </session-factory> </hibernate-configuration>
4.3.3. 第三步:创建HibernateUtils帮助类
package org.chu.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtils { public static final SessionFactory SESSION_FACTORY=HibernateUtils.getSessionFactory(); //1.获得会话工厂 private static SessionFactory getSessionFactory() { //1.创建配置对象 Configuration configuration=new Configuration(); //2.读取配置文件,默认路径为classpath:hibernate.cfg.xml Configuration configure = configuration.configure(); //3.创建会话工厂 SessionFactory factory = configure.buildSessionFactory(); return factory; } //2.获得会话对象 public static Session getSession() { return SESSION_FACTORY.openSession(); } public static void main(String[] args) { System.out.println(HibernateUtils.getSession()); } }
4.3.4. 第四步:创建实体类
package org.chu.pojo; import java.util.Date; public class Student { private Integer studentId;//INT(11) NOT NULL AUTO_INCREMENT COMMENT '学生编号', private String studentName;//VARCHAR(50) NOT NULL COMMENT '学生名', private String studentPwd;//VARCHAR(50) NOT NULL COMMENT '密码', private Integer studentStatus;//INT(11) NOT NULL COMMENT '学生状态', private Date createDate;//DATETIME NOT NULL COMMENT '创建日期', public Integer getStudentId() { return studentId; } public void setStudentId(Integer studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public String getStudentPwd() { return studentPwd; } public void setStudentPwd(String studentPwd) { this.studentPwd = studentPwd; } public Integer getStudentStatus() { return studentStatus; } public void setStudentStatus(Integer studentStatus) { this.studentStatus = studentStatus; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } }
4.3.5. 第五步:创建映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="org.chu.pojo.Student" table="tb_student"> <!-- 指定主键对应关系 问题:为什么ID字段需要单独分开? 答:由于不同数据库的ID生成策略是有差异的,所以我们需要手工指定数据库的ID生成策略 --> <id name="studentId" column="student_id"> <!-- 数据库内置的自增长策略 identity:使用内置的自增长策略 native:使用数据库的内置策略 --> <generator class="identity"></generator> </id> <!-- 指定普通属性的对应关系 --> <property name="studentName" column="student_name"></property> <property name="studentPwd" column="student_pwd"></property> <property name="studentStatus" column="student_status"></property> <property name="createDate" column="create_date"></property> </class> </hibernate-mapping>
package org.chu.test;4.3.6. 第六步:测试插入
import org.chu.pojo.Student; import org.chu.utils.HibernateUtils; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; public class StudentDAOTest { @Test public void save() { try { //第一步:获得操作对象 Session session = HibernateUtils.getSession(); //第二步:启动事务 Transaction transaction = session.beginTransaction(); Student student=new Student(); student.setStudentName("张三"); //第三步:插入 session.save(student); //第四步:提交事务 transaction.commit(); //第五步:关闭 session.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
通过入门示例,我们果然实现了不要编写SQL语句,通过实体类对象就可以操作数据库了。
5. Hibernate主键策略
策略名 |
说明 |
|
increment |
increment策略是指,不使用数据库本地的自增长策略,而是由程序(Hibernate框架)产生一个自增长的ID值,赋予数据库. |
|
idenitty |
identity策略,指定使用数据库里面的ID自增长策略. 只能用于有ID自增长功能的数据库,如:MySQL,SQLServer.. 不支持没有ID自增长策略的数据库,如Oracle,DB2.. |
|
sequence |
使用序列的实现ID生成策略,主要用于有序列的数据库.如:Oracle,DB2,如果不支持序列的数据库(如:MYSQL),该策略会使用一个表模拟序列。 |
|
native |
使用数据库本地的策略,就是数据库里面使用怎么样的策略就用什么策略,HIbernate不做任何的判断.如:MySQL数据库使用了increment_auto,自增长策略.使用native.表示直接调用数据库里面的increment_auto策略. |
|
uuid |
就是数据库的主键是使用一个唯一的字符串的来存储.这个唯一的字符串就是UUID |
|
assigned |
assigned策略,就是不使用主键生成策略,由手工输入ID. |
6. HQL入门
--使用入门示例的基础修改,StudentDAO类
6.1. 查询所有数据
// 查询所有的数据,通过HQL @SuppressWarnings("unchecked") @Test public void findAll() { try { // 第一步:获得操作对象 Session session = HibernateUtils.getSession(); Query query = session.createQuery("from Student"); List<Student> students = query.list(); for (Student student : students) { System.out.println("学生名:" + student.getStudentName()); } // 第五步:关闭 session.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
6.2. 统计记录
// 查询所有的记录数 @Test public void count() { try { // 第一步:获得操作对象 Session session = HibernateUtils.getSession(); Query query = session.createQuery("select count(*) from Student"); Long count = (Long) query.uniqueResult(); System.out.println(count); // 第五步:关闭 session.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
6.3. 模糊查询
//需求:查询有张字的记录 @Test public void findByCondition() { try { // 第一步:获得操作对象 Session session = HibernateUtils.getSession(); Query query = session.createQuery("from Student s where s.studentName like :sname"); query.setParameter("sname", "%张%"); List<Student> students = query.list(); for (Student student : students) { System.out.println("学生名:" + student.getStudentName()); } // 第五步:关闭 session.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
6.4. 条件删除
//通过条件删除,删除有李字的记录 @Test public void deleteByName() { try { // 第一步:获得操作对象 Session session = HibernateUtils.getSession(); Query query = session.createQuery("delete from Student s where s.studentName like ? "); //从左到右,第一参数为0 query.setParameter(0, "%李%"); int executeUpdate = query.executeUpdate(); System.out.println(executeUpdate); // 第五步:关闭 session.close(); } catch (Exception e) { e.printStackTrace(); } }
7. Hibernate 关联关系
7.1. 说明
Hibernate框架支持,通过配置映射关系,实现多表关联查询。
7.2. 准备SQL脚本
SET SESSION FOREIGN_KEY_CHECKS=0; /* Drop Tables */ DROP TABLE IF EXISTS tb_result; DROP TABLE IF EXISTS tb_student_identifer; DROP TABLE IF EXISTS tb_student_teacher; DROP TABLE IF EXISTS tb_student; DROP TABLE IF EXISTS tb_teacher; /* Create Tables */ -- 成绩表 CREATE TABLE tb_result ( result_id int NOT NULL AUTO_INCREMENT COMMENT '成绩编号', result_subject varchar(50) COMMENT '科目', result_score float COMMENT '分数', student_id int NOT NULL COMMENT '学生编号', PRIMARY KEY (result_id) ) COMMENT = '成绩表'; -- 学生表 CREATE TABLE tb_student ( student_id int NOT NULL AUTO_INCREMENT COMMENT '学生编号', student_name varchar(50) COMMENT '学生名', student_pwd varchar(50) COMMENT '密码', PRIMARY KEY (student_id) ) COMMENT = '学生表'; -- 学生身份信息表 CREATE TABLE tb_student_identifer ( student_id int NOT NULL COMMENT '学生编号', student_idcard varchar(30) COMMENT '身份证号码', student_number varchar(50) COMMENT '学号', PRIMARY KEY (student_id) ) COMMENT = '学生身份信息表'; -- 学生教师关系表 CREATE TABLE tb_student_teacher ( student_id int NOT NULL COMMENT '学生编号', teacher_id int NOT NULL COMMENT '教师编号' ) COMMENT = '学生教师关系表'; -- 教师表 CREATE TABLE tb_teacher ( teacher_id int NOT NULL AUTO_INCREMENT COMMENT '教师编号', teacher_name varchar(50) COMMENT '教师名字', teacher_pwd varchar(50) COMMENT '登录密码', PRIMARY KEY (teacher_id) ) COMMENT = '教师表';
7.3. 一对一的关系
7.3.1. 需求
配置一对一的关系。通过学生信息,查询学生的身份信息。
|
注意:我们通过入门示例修改代码。框架配置代码忽略了。
7.3.2. 配置步骤说明
配置表与表的关系,步骤就两步。
第一步:根据数据库设计,将表与表之间的关系建立在实体类里面。
第二步:在对应的映射文件,配置映射的关系。
7.3.3. 配置步骤
第一步:建立学生表与学生身份表的实体类的关系
package org.chu.pojo; public class Student { private Integer studentId;// '学生编号', private String studentName;// '学生名', private String studentPwd;// '密码', //需求,通过Student查询StudentIdentifer表的记录,需要建立关系。 //student与student_identifer是一对一的关系。所以使用引用 private StudentIdentifer studentIdentifer; public StudentIdentifer getStudentIdentifer() { return studentIdentifer; } public void setStudentIdentifer(StudentIdentifer studentIdentifer) { this.studentIdentifer = studentIdentifer; } //补全get、set方法 }
第二步:配置映射文件的映射关系
<hibernate-mapping> <class name="org.chu.pojo.Student" table="tb_student"> <id name="studentId" column="student_id"> <generator class="identity"></generator> </id> <!-- 指定普通属性的对应关系 --> <property name="studentName" column="student_name"></property> <property name="studentPwd" column="student_pwd"></property> <!-- 配置与StudentIdentifer的一对一的关系 --> <one-to-one name="studentIdentifer" foreign-key="student_id"></one-to-one> </class> </hibernate-mapping>
第三步:测试代码
// 需求:通过ID查询学生表的信息,再查询学生的身份信息。 @Test public void findById() { Session session = HibernateUtils.getSession(); // 通过ID查询使用get方法。 Student student = session.get(Student.class, 1); System.out.println("编号:" + student.getStudentId() + "学生名:" + student.getStudentName()); // 注意:如何通过student对象查询到studentIdentifer表的记录, // (1)需要将表与表之间的关联关系建立在实体类里面。(2)并且配置好映射关系。 StudentIdentifer identifer = student.getStudentIdentifer(); System.out.println("学生身份证:" + identifer.getStudentIdcard()); session.close(); } @Test public void findAll() { Session session = HibernateUtils.getSession(); // 通过ID查询使用get方法。 Query query = session.createQuery("select s from Student s"); List<Student> students = query.list(); for (Student student : students) { System.out.println("编号:" + student.getStudentId() + "学生名:" + student.getStudentName()); // 注意:如何通过student对象查询到studentIdentifer表的记录, // (1)需要将表与表之间的关联关系建立在实体类里面。(2)并且配置好映射关系。 StudentIdentifer identifer = student.getStudentIdentifer(); System.out.println("学生身份证:" + identifer.getStudentIdcard()); } session.close(); } }
7.4. 一对多的关系
7.4.1. 需求
通过学生表的记录,查询学生的成绩记录。
|
7.4.2. 配置步骤
第一步:配置实体类的关联关系
在学生实体类Student加上以下代码
//学生与成绩的关系是,一对多。所以使用集合, private Set<Result> results; public Set<Result> getResults() { return results; } public void setResults(Set<Result> results) { this.results = results; }
<!-- 配置学生与成绩的,一对多的关系 -->第二步:配置学生映射关系文件
<!-- set标签,用于配置Set集合的属性 --> <set name="results" > <!-- 用于指定外键字段 --> <key column="student_id"></key> <!-- 用于指定一对多的关系,class:指定集合元素类性 --> <one-to-many class="org.chu.pojo.Result" /> </set>
7.5. 多对一配置
7.5.1. 需求
查询成绩的信息,在通过成绩信息查询学生信息。
7.5.2. 配置步骤
第一步:配置实体类的关系
在成绩实体类表(Result)表配置学生实体类的关系。
//配置成绩与学生的关系。多对一的关系。使用引用 private Student student; public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; }
第二步:配置映射文件的关系
<hibernate-mapping package="org.chu.pojo"> <class name="Result" table="tb_result"> <id name="resultId" column="result_id"> <generator class="identity" /> </id> <property name="resultSubject" column="result_subject" /> <property name="resultScore" column="result_score" /> <!-- <property name="studentId" column="student_id" insert="false" update="false" /> --> <!-- 配置成绩与学生,多对一的关系 name:配置多对一,引用的属性名, column:配置关联的外键字段 --> <many-to-one name="student" column="student_id"></many-to-one> </class> </hibernate-mapping>
注意:要注释掉,原来外键字段的属性配置。
7.6. 多对多配置
需求:通过学生的记录查询学生的教师记录。
|
7.6.1. 配置步骤
第一步:配置实体类的关系
配置学生表与教师表的关系,在Student实体类加上以下代码
//配置学生与教师的关系,多对多。 private Set<Teacher> teachers; public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; }
第二步:配置映射文件的关系
<!-- 配置学生与教师的多对多关系 --> <set name="teachers" table="tb_student_teacher"> <!-- 指定本表在中间表的外键 --> <key column="student_id"></key> <!-- 指定多对多的关系 class返回的集合,元素的类型 column关联表在中间表的外键 --> <many-to-many class="org.chu.pojo.Teacher" column="teacher_id"></many-to-many> </set>
第三步:测试代码
// 需求:通过ID查询学生表的信息,再查询学生的教师信息。 @Test public void findById() { Session session = HibernateUtils.getSession(); // 通过ID查询使用get方法。 Student student = session.get(Student.class, 1); System.out.println("编号:" + student.getStudentId() + "学生名:" + student.getStudentName()); Set<Teacher> teachers = student.getTeachers(); for (Teacher teacher : teachers) { System.out.println("教师名:"+teacher.getTeacherName()); } session.close(); }