Hibernate搭建与入门

Hibernate出现背景

在Hibernate等ORM框架出现之前,Java Web应用通常使用JDBC来进行持久层的数据库访问等操作,但是JDBC存在着很多缺点,比如实现业务逻辑的代码和数据库访问的代码掺杂在一起,使程序结构不清晰,可读性差;在程序代码中嵌入面向关系的SQL语句,使开发人员不能完全运用面向对象的思维来编写程序;业务逻辑和关系数据模型绑定,如果关系模型发生变化,需要手工修改程序代码中所有相关的SQL语句,增加了程序维护的难度等等。

导入jar包

需要的jar包

如何配置Hibernate

  1. 核心配置文件名和位置的固定
    * 位于:src目录下
    * 名称 hibernate.cfg.xml
  2. 配置的四要素
    * 数据库是必须的
    * 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>

映射文件

细节 不懂的可以对照代码看

  1. 映射配置文件名称和位置没有要求
  2. 映射配置文件中,标签name属性值写实体类相关内容
    * class 标签 name 属性值是实体类的全路径
    * id 标签和 property 标签 name 属性值是实体类属性名
  3. id 标签和 property标签,column 属性可以省略,省略后字段名会和name属性值一样(一般不建议省略)
  4. 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();
    }

解释:首先底层做的一件事就是

  1. 到src下面找名称是hibernate.cfg.xml这个文件 把这个文件加载到对象中
  2. 通过这个对象读取hibernate配置文件中的内容,并构建一个session工厂,在这个过程中,我们核心配置文件的<property name="hibernate.hbm2ddl.auto">update</property>配置就起作用了,他会根据映射文件,在我们配置好的数据库中把表创建
  3. 获取本地线程绑定session可以不用做 后面我会跟新一张解释绑定本地线程的好处 简单的来说 如果绑定本地资源的话就不用手动关闭session了,如果手动关闭就会报这个错org.hibernate.SessionException.Session war already closed 会话已经结束
  4. 获取session对象怎么理解呢? 我们在JDBC中是不是有一个创建连接Connection conn = DriverManager.getConnection(url, user, password); 我们这里可以把创建session对象看成这个步骤
  5. crud的操作后面更
  6. 开启事物 和 提交事物就不用多说了把 不能理解的可以把开启事物当成一个盒子 而我们的crud操作就是放入盒子里面的内容 提交事物呢?就是打包盒子,邮寄给JVM虚拟机来执行操作
  7. 释放资源也不用多说 后打开的先释放 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操作和它的缓存机制,下期见咯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值