Hibernate快速入门
Hibernate出现背景
在Hibernate等ORM框架出现之前,Java Web应用通常使用JDBC来进行持久层的数据库访问等操作,但是JDBC存在着很多缺点,比如实现业务逻辑的代码和数据库访问的代码掺杂在一起,使程序结构不清晰,可读性差;在程序代码中嵌入面向关系的SQL语句,使开发人员不能完全运用面向对象的思维来编写程序;业务逻辑和关系数据模型绑定,如果关系模型发生变化,需要手工修改程序代码中所有相关的SQL语句,增加了程序维护的难度等等。
导入jar包
如何配置Hibernate
- 核心配置文件名和位置的固定
* 位于:src目录下
* 名称 hibernate.cfg.xml - 配置的四要素
* 数据库是必须的
* hibernate中部分可选(什么可选 直接看代码)
* 核心配置文件必须的
* 映射文件必须的
核心配置文件
目录 src/hibernate.cfg.xml
<?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="connection.url">jdbc:mysql://localhost:3306/StudentSystem?characterEncoding=UTF-8</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">数据库账号</property>
<property name="hibernate.connection.password">数据库密码</property>
<!--配置数据库的方言
在mysql里面实现分页 关键字limit ,只能使用myslq里面
在oracle数据库,实现分页rownum-->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--第二部分:配置hibernate信息,可选-->
<!--输出底层的sql语句 是否要把sql语句打印到控制台-->
<property name="show_sql">true</property>
<!--输出底层sql语句格式化-->
<property name="format_sql">true</property>
<!--hibernate会帮我们创建表,但是需要配置之后才能使用 会检查你的表是否存在 如果不存在会自动创建表-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--第三部分:把映射文件放到核心配件中 必须的 -->
<mapping resource="映射文件的目录 也就是👇的代码路径"/>
</session-factory>
</hibernate-configuration>
映射文件
细节 不懂的可以对照代码看
- 映射配置文件名称和位置没有要求
- 映射配置文件中,标签name属性值写实体类相关内容
* class 标签 name 属性值是实体类的全路径
* id 标签和 property 标签 name 属性值是实体类属性名- id 标签和 property标签,column 属性可以省略,省略后字段名会和name属性值一样(一般不建议省略)
- property 标签,type 属性,设置生成表字段类型,基本不用。会自动生成对应的类型
一个实体对应一个映射文件
实体类
import java.util.Objects;
/**
* @author alone
* @program: SSH_CRM
* 用户实体类
* @date 2019年 11月30日 11:30:55
*/
public class User {
private Integer uid;
private String username;
private String password;
private String address;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(uid, user.uid) &&
Objects.equals(username, user.username) &&
Objects.equals(password, user.password) &&
Objects.equals(address, user.address);
}
@Override
public int hashCode() {
return Objects.hash(uid, username, password, address);
}
}
映射文件
<?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">
<hibernate-mapping>
<!-- 1 配置类和表对应
class标签
name属性:实体类全路径
table属性:数据库表名称
-->
<class name="cn.itcast.entity.User"/*一个映射文件对应一个实体类,这里要映射到你对应的实体类的路径*/ table="t_user">
<!-- 2 配置实体类id和表id对应
hibernate要求实体类有一个属性唯一值
hibernate要求表有字段作为唯一值
-->
<!-- id标签 id标签要单独写 要设置ID的自动增长 告诉数据库 id是主键
name属性:实体类里面id属性名称
column属性:生成的表字段名称
-->
<id name="uid" column="uid">
<!-- 设置数据库表id增长策略 native:生成表id值就是主键自动增长-->
<generator class="native"></generator>
</id>
<!-- 配置其他属性和表字段对应
name属性:实体类属性名称
column属性:生成表字段名称
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
配置搞定了如何让他自动创建表呢?
首先我们需要写一个测试代码
@Test
public void test() {
/**
* 第一步 加载hibernate核心配置文件
*/
Configuration cfg = new Configuration().configure();
/**
* 第二步 创建SessionFactory对象
* 读取hibernate核心配置文件内容,创建sessionFactory
* 在过程中,根据映射关系,在配置数据库里面把表创建
*/
SessionFactory sessionFactory = cfg.buildSessionFactory();
//获取与本地线程绑定的session
sessionFactory.getCurrentSession();
/**
* 第三步 使用SessionFactory创建session对象
*/
// 类似于连接
Session session = sessionFactory.openSession();
// 第四步 开启事务
Transaction tx = session.beginTransaction();
//第五步 写具体逻辑 crud操作
//暂时可以不做
//第六步 提交事务
tx.commit();
//第六步 释放资资源
session.close();
sessionFactory.close();
}
解释:首先底层做的一件事就是
- 到src下面找名称是hibernate.cfg.xml这个文件 把这个文件加载到对象中
- 通过这个对象读取hibernate配置文件中的内容,并构建一个session工厂,在这个过程中,我们核心配置文件的
<property name="hibernate.hbm2ddl.auto">update</property>
配置就起作用了,他会根据映射文件,在我们配置好的数据库中把表创建- 获取本地线程绑定session可以不用做 后面我会跟新一张解释绑定本地线程的好处 简单的来说 如果绑定本地资源的话就不用手动关闭session了,如果手动关闭就会报这个错
org.hibernate.SessionException.Session war already closed
会话已经结束- 获取session对象怎么理解呢? 我们在JDBC中是不是有一个创建连接
Connection conn = DriverManager.getConnection(url, user, password);
我们这里可以把创建session对象看成这个步骤- crud的操作后面更
- 开启事物 和 提交事物就不用多说了把 不能理解的可以把开启事物当成一个盒子 而我们的crud操作就是放入盒子里面的内容 提交事物呢?就是打包盒子,邮寄给JVM虚拟机来执行操作
- 释放资源也不用多说 后打开的先释放 session一直开着肯定占用资源的 所以我们不用就把他释放掉
简单的添加操作
@Test
/**
* 第一步 加载hibernate核心配置文件
*/
Configuration cfg = new Configuration().configure();
/**
* 第二步 创建SessionFactory对象
* 读取hibernate核心配置文件内容,创建sessionFactory
* 在过程中,根据映射关系,在配置数据库里面把表创建
*/
SessionFactory sessionFactory = cfg.buildSessionFactory();
/**
* 第三步 使用SessionFactory创建session对象
*/
// 类似于连接
Session session = sessionFactory.openSession();
// 第四步 开启事务
Transaction tx = session.beginTransaction();
//第五步 写具体逻辑 crud操作
//添加功能
User user = new User();
user.setUsername("小王");
user.setPassword("250");
user.setAddress("日本");
//调用session的方法实现添加
session.save(user);
//第六步 提交事务
tx.commit();
//第六步 释放资资源
session.close();
sessionFactory.close();
}
是不是感觉相比于我们搞核心配置文件 和 映射配置文件 发现其实并不比JDBC操作简单到哪去 不要灰心 当我们接触到Mybatis+springBoot开发到时候你会发现增删改成就一个注解就可以搞定 先给你们看看有多简洁
//查询用户登陆账号密码是否存在
@Select({
"SELECT * FROM `user` WHERE u_login = #{login} AND u_psd = #{psd}"
})
User login(@Param(value = "login") String login, @Param(value = "psd") String psd);
让我们对比一下JDBC连接
void template( throws Exception t
String url ="jdbc: mysql: /localhost: 3306/jdbc";
String user ="root
String password =":
Connection conn=null
Statement st=null
Resultset rs=null
//.注册驱动
Class.forName("com. mysqljdbc Driver");
try {
// 建立连接
conn = JdbcUtils.getConnection();
// 创建语句
st = conn.createStatement();
// 执行语句
rs = st.executeQuery("select * from user");
// 结果处理
while (rs.next()) {
System.out.println(rs.getObject(1));
}
} finally {
try {
if (rs != null)
rs.close();
} catch (
SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
话不多说 进入下一个话题
如果我们每一次进行crud操作的时候都来写这么多代码是不是太繁琐了,接下来我们自己来封装一下
封装一个hibernate的工具类
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Hibernateg工具类
*
* @author alone
* @date 2019年 11月20日 11:25:10
*/
public class HibernateUtils {
private static final Configuration configuration;
private static final SessionFactory sessionFactory;
static {
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
//Session获取
public static Session openSession() {
return sessionFactory.openSession();
}
public static void main(String[] args) throws InterruptedException {
}
}
疑问?为什么工具类里面要放一个空的main方法?
- 我们这样想如果我们只是想单纯的通过映射文件创建表怎么办?是不是还要按照上面讲的的重新执行一遍?
这样太繁琐了,我们可以看到加载hibernate.cfg.xml和创建session工厂我们是不是放到了静态代码块中,而静态代码块的特点是什么?
随着类的加载而加载,且只加载一次,这样就避免了我们每次操作的时候都要去创建对象,这时候如果我们执行main方法是不是首先把这个类加载到JVM中?类加载完成之后我们就会来加载静态代码块中内容,这样我们的表就可以创建了
对比有工具类后的添加操作
@Override
public boolean add(Teacher teacher) {
Session session = null;
Transaction transaction = null;
try {
//通过工具类获取session对象
session = HibernateUtils.openSession();
//开启事物
transaction = session.beginTransaction();
User user = new User();
user.setUsername("小王");
user.setPassword("250");
user.setAddress("日本");
session.save(user);
System.err.println("打印添加到用户信息" + user);
//提交事物
transaction.commit();
return true;
} catch (Exception e) {
e.printStackTrace();
//事物回滚
transaction.rollback();
} finally {
session.close();
}
return false;
}
好了,基本入门基本讲完了,下期更新hibernate的crud操作和它的缓存机制,下期见咯