一.hibernate的简介
- Hibernate是数据持久化工具,是一个开源的ORM(对象关系映射)解决方案
-
Hibernate底层封装了JDBC,简化数据库操作
-
Hibernate面向对象,不需要编写SQL语句,支持多种数据库
优点
- Hibernate功能强大,与JDBC相比,代码量大大减少,提高持久化代码的开发速度,降低维护成本
- Hibernate支持面向对象编程,不需要编写SQL语句
- 可移植性好
- Hibernate框架开源免费
缺点
- 不适合以数据为中心大量使用存储过程的应用
-
大规模的批量插入、修改和删除不适合用Hibernate框架
二.创建项目进行CRUD操作
1.新增操作(使用opensession方式)
1.1. 创建maven项目,导入hibernate、mysql、jdbc依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.27.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
1.2. 创建hibernate.cfg.xml配置文件,放在resource目录下
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 必填项,驱动、用户名、密码、连接路径、方言 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/ceshi?useUnicode=true&characterEncoding=UTF-8</property>
<!-- 使用MySQL的innodb引擎 支持事务和外键;myISAM引擎不支持事务和外键-->
<property name="hibernate.dialect.storage_engine">innodb</property>
</session-factory>
</hibernate-configuration>
1.3. 创建test数据库及表user,添加持久类User并提供toString方法
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
1.4. 在resource/mapper/目录下添加User.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>
<!--class标签:用于关联实体类,通过name属性指定实体类
name属性:表示持久化类的全限定名
table属性:表示持久化类对应数据库的表名,类与表名一致时,可省略-->
<class name="com.entity.User" table="user" >
<!-- id:Id标签表示持久化类的OID(对象主键属性)和表的主键映射
name:填写该实体类的属性名称(严格区分大小写)
column:填写数据库表中的列名称(不区分大小写),当列名与实体类的属性名相同时可以省略
type:填写该属性的数据类型
-->
<id name="id" column="id" type="java.lang.Integer">
<!-- generator:用于指定主键的生成策略
class元素:用于指定主键的生成策略
Param标签:用于传递参数
assigned:主键由程序提供(非自增)默认的生成策略
increment:主键自增,支持long、int、short类型主键,先查询表中最大的id值,加1后使用 select max(deptno) from dept
identity:自动增长,支持标识列的数据库才能使用,例如:mysql、SQLServer
sequence:序列,Oracle等支持序列的数据库可以使用
native:自动增长,但会根据数据库的不同自动选择
uuid:根据uuid算法生成uuid字符串做主键
-->
<generator class="increment"/>
</id>
<!-- property:定义持久化类的属性和数据库表中的字段的对应关系
name属性:表示持久化类属性的名称,和属性的get方法匹配
type属性:持久化类属性的类型
column属性:持久化类属性对应到表中的字段名称(填数据表中属性的字段)
-->
<!--column:用于指定其父元素代表的持久化类属性对应表中的列名称
name:表示字段名称
length:表示字段长度
not-null设定是都不能为null,设置为true表示不能为null
-->
<property name="username" type="java.lang.String" column="username"/>
<property name="password" type="java.lang.String">
<column name="password"/>
</property>
</class>
</hibernate-mapping>
1.5. 在hibernate.cfg.xml中引入User.hbm.xml
1.6. 创建类测试,使用openSeesion必须关闭session
public class TestUser {
@Test
public void testAdd() {
//1.读取hibernate配置文件
Configuration configuration = new Configuration().configure();
//2.创建SessionFactory对象
SessionFactory sessionFactory = configuration.buildSessionFactory();
//3.创建Session对象(打开session)
//注意:通过openSession()方法打开Session必须关闭session
Session session = sessionFactory.openSession();
//4.开启事务
Transaction transaction = session.beginTransaction();
try {
//5.准备数据
User user = new User();
user.setUsername("小李");
user.setPassword("123");
//6.持久化数据
session.save(user);
//7.提交事务
transaction.commit();
} catch (HibernateException e) {
e.printStackTrace();
//8.回滚事务
transaction.rollback();
} finally {
//9.关闭资源
session.close();
}
}
}
1.7. 查询一下结果
1.新增操作(使用getCurrentSession方式)
1.1.在hibernate.cfg.xml中配置线程上下文,必须配置
1.2. 总结
2.根据主键查询
2.1. 封装工具类
public class HibernateUtil {
//会话工厂对象
private static SessionFactory sessionFactory;
//使用静态代码读取配置文件
static {
//1.读取并解析配置文件
Configuration configuration = new Configuration().configure();
//2.创建会话工厂对象
sessionFactory = configuration.buildSessionFactory();
}
public static Session getSession() {
//return sessionFactory.openSession();//需要关闭资源
return sessionFactory.getCurrentSession();//需要在hibernate配置文件中配置线程上下文
}
public static void closeSession(Session session) {
//判断Session是否为空或Session是否处于打开状态
if (session != null && session.isOpen()) {
session.close();//关闭session 40
}
//关闭工厂对象
sessionFactory.close();
}
}
2.2. 使用get()方法查询
1.根据主键查询,主键不存在返回null
2.立即加载:无论是否使用到该对象,都会去查询数据库,效率低
3.获取Session对象,有两种情况,分别是:
1.通过openSession()方式获取,则不需要加入事务
2.通过getCurrentSession()方式获取,则查询需要加入事务
2.3. 编写代码
public class TestUser {
@Test
public void testGetDept() {
//1.获取Session
Session session = HibernateUtil.getSession();
//2.开启事务
Transaction transaction = session.beginTransaction();
//3.根据主键查询
User user = session.get(User.class, 1);
System.out.println(user);
//4.关闭资源
HibernateUtil.closeSession(session);
}
}
2.4. 使用load()方法查询
1.根据主键查询,主键不存在会报错,发生ObjectNotFoundException(找不到对象)
2.延迟加载(懒加载):如果没有使用到该对象,则不会查询数据库
2.5. 编写代码测试
public class TestUser {
public static void main(String[] args){
//1.获取Session
Session session = HibernateUtil.getSession();
//2.开启事务
Transaction transaction = session.beginTransaction();
//3.根据主键查询
User user = session.load(User.class, 2);
System.out.println(user);
//4.关闭资源
HibernateUtil.closeSession(session);
}
}
3. 根据主键修改信息
3.1. 传统方式-如果某个属性没有被赋值,那么原来的属性会被清空
3.2.这里我们没有设置password的值,发现数据库的属性值被清空了
3.3. 先查询后修改-没有赋值的属性不会被清空,保留原来的值,会发出两条SQL语句,分别是查询和修改
3.4. 我们先将id为1的password赋值为555
3.5. 测试一下
3.6. 查询一下数据库信息,发现其他没有赋值的属性没有被清空
4.根据主键删除信息
4.1.再次查看数据库的信息-成功删除
三.Hibernate中java对象的三种状态
1.java对象的三种状态
2.三种状态之间的转变
3.脏机制和刷新缓存机制
4.持久化方法
4.1. saveOrUpdate()
新增:没有指定主键的情况下会执行新增操作
修改:当指定的主键是存在的,执行修改操作,若主键不存在,会触发异常
生成策略:用此方法主键生成策略不能是assigned
4.2. 查询数据库信息,我们将修改id为2的信息
4.3.指定主键,测试
4.4. 查询数据信息,发现已经被修改
4.5. 测试不指定主键方式
4.6. 查询数据库信息,发现新增了一条数据
4.7. merge()方法
新增-当没有指定主键或者主键不存在时(先根据之间查询,对象为空则新增)执行新增操作
修改-执行的主键是存在的执行修改操作
四.Hibernate关联映射
1.表之间的关系
1.1. hibernate表关系分析步骤
第一步:首先确定两张表的关系
第二步:在数据库中实现两张表的关系
第三步:在实体类中描述出两个实体类的关系
第四步:配置出实体类的数据库表的关系映射(重点)
2.单向多对一关联
2.1. 需求:单项添加员工,配置多对一(多个员工对应一个部门)
2.2. 环境准备:
2.2.1. Department实体类
public class Department {
private Integer deptNo;
private String deptName;
private String location;
public Integer getDeptNo() {
return deptNo;
}
public void setDeptNo(Integer deptNo) {
this.deptNo = deptNo;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
2.2.2. Enployee实体类
public class Employee {
private Integer empNo;//员工编号
private String empName;//员工姓名
private String job;//职位
private Double salary;//薪资
private Integer deptNo;//部门编号
private Date hireDate;//入职时间
public Integer getEmpNo() {
return empNo;
}
public void setEmpNo(Integer empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Integer getDeptNo() {
return deptNo;
}
public void setDeptNo(Integer deptNo) {
this.deptNo = deptNo;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
}
2.2.3. 准备Department.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>
<class name="com.entity.Department" table="department" >
<id name="deptNo" column="deptNo" type="java.lang.Integer">
<generator class="increment"/>
</id>
<property name="deptName" type="java.lang.String" column="deptName"/>
<property name="location" type="java.lang.String">
<column name="location"/>
</property>
</class>
</hibernate-mapping>
2.3.4. 准备Employee.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>
<class name="com.entity.Employee" table="employee" >
<id name="empNo" column="empNo" type="java.lang.Integer">
<generator class="increment"/>
</id>
<property name="empName" type="java.lang.String" column="empName"/>
<property name="job" type="java.lang.String" column="job"/>
<property name="salary" type="java.lang.Double" column="salary"/>
<property name="deptNo" type="java.lang.Integer" column="deptNo"/>
<property name="hireDate" type="java.util.Date" column="hireDate"/>
</class>
</hibernate-mapping>
2.3.5. 导入映射文件到hibernate.cfg.xml中
2.3.6. 修改员工类-将原来外键属性deptNo修改成类类型Department的属性:将deptNo变成department属性,别忘了把deptNo的getter和setter方法删除
2.3.7. 映射文件Employee.hbm.xml中部门编号配置修改成以下配置:
2.3.8. 在部门表中添加一行数据,写代码测试一下
public class TestManyToOne {
public static void main(String[] args) {
//获取Session
Session session = HibernateUtil.getSession();
//开启事务
Transaction transaction = session.beginTransaction();
try {
//创建对象
Employee employee = new Employee();
employee.setEmpName("汤姆");
employee.setHireDate(new Date());
employee.setJob("经理");
employee.setSalary(10000D);
//获取部门信息
Department department = session.get(Department.class,1);
employee.setDepartment(department);//设置员工所在的部门
// 保存员工
session.save(employee);
//提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚
transaction.rollback();
}finally {
//关闭资源
HibernateUtil.closeSession(session);
}
}
}
2.3.9. 查询数据库信息,使用关联查询-成功