复习_Hibernate_基础

1.引言

1.1 为什么要学习Hibernate

使用传统的JDBC开发应用系统时,如果是小型应用系统,并不觉得有什么麻烦,但是对于大型应用系统的开发,使用JDBC就会显得力不从心。

例A:对几十、几百张包含几十个字段的表进行插入操作时,编写的SQL语句不但很长,而且繁琐,容易出错;
例B:在读取数据时,需要写多条getXxx语句从结果集中取出各个字段的信息,不但枯燥重复,并且工作量非常大。

1.2 ORM概述

在这里插入图片描述
ORM即Object Relation Mapping 对象关系映射。

对象-关系映射(简称ORM),是随着面向对象的软件开发方法发展而产生的。用来把对象模型(实体类)表示的对象映射到基于SQL的关系模型数据库结构中去。这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作实体对象的属性和方法。ORM技术是在对象和关系之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化。
在这里插入图片描述
ORM原理如下图所示:
在这里插入图片描述

简单的说就是把我们程序中的实体类和数据库表建立起来对应关系。
明确:操作实体类就相当于操作数据库表


2.Hibernate入门

2.1 导包

在这里插入图片描述
在这里插入图片描述

2.2 创建数据表和实体类

1.创建数据表

/*创建客户表*/
CREATE TABLE `cst_customer` (
  `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
  `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
  `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
  `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
  `cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
  `cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8;

2.Customer持久化类
持久化类是应用程序中的业务实体类,这里的持久化是指类的对象能够被持久化保存到数据库中。Hibernate使用普通Java对象(Plain Old Java Object),即POJO的编程模式来进行持久化。POJO类中包含的是与数据库表相对应的各个属性,这些属性通过getter和setter方法来访问,对外部隐藏了内部的实现细节。
在项目src目录下,创建cn.itcast.domain包,并在包中创建实体类Customer(对应数据库表cst_customer),Customer类包含与cst_customer数据表字段对应的属性,以及相应的getXxx ()和setXxx ()方法。
在这里插入图片描述

public class Customer implements Serializable {
    private Long custId;// 客户编号
    private String custName;// 客户名称
    private String custSource;// 客户信息来源
    private String custIndustry;// 客户所属行业
    private String custLevel;// 客户级别
    private String custAddress;// 客户联系地址
    private String custPhone;// 客户联系方式

    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }
    @Override
    public String toString() {
        return "Customer [custId=" + custId + ", custName=" + custName
                + ", custSource=" + custSource + ", custIndustry="
                + custIndustry + ", custLevel=" + custLevel + ", custAddress="
                + custAddress + ", custPhone=" + custPhone + "]";
    }
}

3.编写映射配置文件(xml)
之前编写的实体类Customer目前还不具备持久化操作的能力,而Hibernate需要知道实体类Customer映射到数据库中的哪个表,以及类中的哪个属性对应数据库表中的哪个字段,这些都需要在映射文件中配置。
在实体类Customer所在的包中,创建一个名称为Customer.hbm.xml的映射文件,在该文件中定义了实体类Customer的属性是如何映射到cst_customer表的列上的。
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入DTD约束
位置:在Hibernate的核心jar包(hibernate-core-5.0.7.Final.jar)中名称为hibernate-mapping-3.0.dtd
明确该文件中的内容:
	实体类和表的对应关系
	实体类中属性和表的字段的对应关系
-->
<!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.itcast.domain"><!-- package属性用于设定包的名称,接下来该配置文件中凡是用到此包中的对象时都可以省略包名 -->
    <!-- class标签
            作用:建立实体类和表的对应关系
            属性:
                name:指定实体类的名称
                table:指定数据库表的名称
     -->
    <class name="Customer" table="cst_customer">
        <!-- id标签
             作用:用于映射主键
             属性:
                 name:指定的是属性名称。也就是get/set方法后面的部分,并且首字母要转小写。
                 column:指定的是数据库表的字段名称
        -->
        <id name="custId" column="cust_id">
            <!-- generator标签:
            作用:配置主键的生成策略。
            属性:
              class:指定生成方式的取值。
              取值之一:native   使用本地数据库的自动增长能力。
              mysql数据库的自动增长能力是让某一列自动+1。但是不是所有数据库都支持这种方式
           -->
            <generator class="native"></generator>
        </id>
        <!-- property标签:
                作用:映射其他字段
                属性:
                    name:指定属性的名称。和id标签的name属性含义一致
                    column:指定数据库表的字段名称
        -->
        <property name="custName" column="cust_name"></property>
        <property name="custSource" column="cust_source"></property>
        <property name="custIndustry" column="cust_industry"></property>
        <property name="custLevel" column="cust_level"></property>
        <property name="custAddress" column="cust_address"></property>
        <property name="custPhone" column="cust_phone"></property>
    </class>
</hibernate-mapping>

4.编写主配置文件(hibernate.cfg.xml)
Hibernate的映射文件(例:Customer.hbm.xml)反映了持久化类和数据库表的映射信息,而Hibernate的配置文件则主要用来配置数据库连接以及Hibernate运行时所需要的各个属性的值。在项目的src下创建一个名称为hibernate.cfg.xml的文件
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入dtd约束:
位置:在核心jar包中的名称为hibernate-configuration-3.0.dtd
-->
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <!-- 配置SessionFactory
      SessionFactory就是一个工厂,用于生产Session对象的。
      Session就是我们使用hibernate操作数据库的核心对象了。
      明确:
          它和我们Web阶段的HttpSession没一点关系。
          此配置文件中的内容不需要背,很多配置都是可以在开发包中找到的。
          但是要求必须知道:
          创建SessionFactory由三部分组成:(缺一不可)
          1、连接数据库的基本信息
          2、hibernate的基本配置
          3、映射文件的位置
          找配置文件的key都是在hibernate的开发包中project文件夹下的etc目录中的hibernate.properties
          路径:...\hibernate-release-5.0.7.Final\project\etc\hibernate.properties
    -->
    <session-factory>
        <!-- 1、数据库的基本信息 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hinbernate_test</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!-- 数据库的方言 -->
        <!-- 新版本的数据库方言:org.hibernate.dialect.MySQL5Dialect -->
        <!-- 老版本的数据库方言:org.hibernate.dialect.MySQLDialect -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- 2、hibernate的基本配置 -->
        <!-- 是否显示SQL语句 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 是否格式化SQL语句 -->
        <property name="hibernate.format_sql">true</property>
        <!-- 3、映射文件的位置 -->
        <mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

5.实现数据持久化操作
在项目中新建一个名称为cn.itcast.dao的包,然后在包中建立一个名为CustomerDao.java的文件

package cn.itcast.dao;

import cn.itcast.domain.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class CustomerDao {
    /**
     * 保存一个客户实体
     * @param c
     */
    public static void save(Customer c){
        //加载主配置文件(hibernate.cfg.xml)
        Configuration cfg=new Configuration().configure();
        //创建SessionFactory对象
        SessionFactory factory=cfg.buildSessionFactory();
        //使用SessionFactory生产一个Session
        Session session=factory.openSession();
        //开启事务
        Transaction tx=session.beginTransaction();
        //保存客户
        session.save(c);
        //提交事务
        tx.commit();
        //释放资源
        session.close();
        factory.close();
    }

    public static void main(String[] args) {
        //创建客户类对象
        Customer c= new Customer();
        c.setCustName("黑马.程序员1");
        //调用对客户进行持久化的方法
        CustomerDao.save(c);
    }
}

6.执行流程
首先创建Configuration类的实例,并通过它来读取并解析配置文件hibernate.cfg.xml。然后创建SessionFactory读取解析映射文件信息,并将Configuration对象中的所有配置信息拷贝到SessionFactory内存中。接下来,打开Session,让SessionFactory提供连接,并开启一个事务,之后创建对象,向对象中添加数据,通过session.save()方法完成向数据库中保存数据的操作。最后提交事务,并关闭资源。
在这里插入图片描述

7.Hibernate的常见配置

7.1 映射文件的配置
之前案例中使用过的Customer.hbm.xml文件,该文件用于向Hibernate提供持久化类到关系型数据库的映射,每个映射文件的的结构基本都是相同的,其普遍的代码形式如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 映射文件的DTD信息 -->
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
hibernate-mapping标签  属于映射文件的顶层标签
属性:package
用于设定包的名称,接下来该配置文件中凡是用到此包中的对象时都可以省略包名 
-->
<hibernate-mapping package="包名">
     <!-- class标签   作用:建立实体类和表的对应关系 
          name 代表的是实体类名称
          table 代表的是数据库表名称
-->
	 <class name="Xxx"  table="xxx">
<!-- id标签   作用:用于映射主键
name  代表的是Xxx类中的属性名
	     column  代表的是xxx表中的字段名
-->
	    <id name="Id" column="id">
	        <!-- generator是主键生成策略 -->
	       <generator class="native"></generator>
	    </id>
	    <!-- property标签  作用:映射其他非主键字段 -->
	    <property name="实体类属性名" column="数据表字段名" ></property>
	 </class>
</hibernate-mapping>

映射文件通常是一个XML文件即可,但一般命名为:类名.hbm.xml

7.2 核心文件的配置
Hibernate的核心配置文件(hibernate.cfg.xml),包含了连接持久层与映射文件所需的基本信息,其配置文件有两种格式,具体如下:

  • 一种是properties属性文件格式的配置文件,它使用键值对的形式存放信息,默认文件名称为hibernate.properties
  • 另一种是XML格式的配置文件,XML配置文件的默认名称为hibernate.cfg.xml

在实际开发项目中,大多数情况会使用XML格式的配置文件。下面将对XML格式的配置文件进行详细介绍。
hibernate.cfg.xml配置文件一般在开发时会放置在类的根路径下(现在是放置在src文件夹下)。配置文件的常用配置信息如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<!-- DTD信息:用来标记约束 -->
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Hibernate相关配置信息 -->
<hibernate-configuration>
<!-- 配置Session工厂信息(全局) -->
  <session-factory>  
	<!-- 必要的配置信息1 : 四本一言(4个基本项,1个方言)-->
	<!-- 4个基本项:四个连接数据库的基本参数 -->
	<!-- 数据库驱动 -->
	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
	<!-- 数据库连接字符串 -->
	<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
     <!-- 数据库登录名 -->
	<property name="hibernate.connection.username">root</property>
	<!-- 数据库登录密码 -->
	<property name="hibernate.connection.password">root</property>
     <!-- 数据库的方言 : 根据配置的方言生成相应的SQL语句 -->
	<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
  <!-- 必要的配置信息2 : hibernate的基本属性 -->
	<!-- 是否显示SQL语句  在控制台打印输出SQL语句-->
	<property name="hibernate.show_sql">true</property>
	<!-- 是否格式化SQL语句 -->
	<property name="hibernate.format_sql">true</property>

<!-- Hibernate的hbm2ddl(数据定义语言:create drop alter ...)属性 -->
<!--	hibernate可以根据映射文件来为我们生成数据库的表结构(但是不能生成数据库)
		hbm2ddl.auto的取值
		* none:不用Hibernate自动生成表
		* create:每次都会创建一个新的表(测试)
		* create-drop:每次都会创建一个新的表,执行程序结束后删除这个表(测试)
		* update:如果数据库中有表,使用原来的表,如果没有表,创建一个新表.可以更新表结构
		* validate:只会使用原有的表.对映射关系进行校验
	-->
	<property name="hibernate.hbm2ddl.auto">update</property>

  <!-- 必要的配置信息3 : 映射文件加载 -->
		<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

在上述代码中,首先进行了xml声明,然后是配置文件的dtd信息,该信息同样可以在核心包hibernate-core-5.0.7.Final.jar下的org.hibernate包中的hibernate-configuration-3.0.dtd文件中找到,只需要复制过来用即可,不需要刻意记忆。

Hibernate配置文件的根元素是hibernate-configuration,该元素包含子元素session-factory,在session-factory元素中又包含多个property元素,这些property元素用来对Hibernate连接数据库的一些重要信息进行配置。例如,上面的配置文件中,使用了property元素配置了数据库的方言、驱动、URL、用户名、密码等信息。最后通过mapping元素的配置,加载出映射文件的信息。

名称用途
hibernate.dialect操作数据库方言
hibernate.connection.driver_class连接数据库驱动程序
hibernate.connection.url连接数据库URL
hibernate.connection.username数据库用户名
hibernate.connection.password数据库密码
hibernate.show_sql在控制台上输出SQL语句
hibernate.format_sql格式化控制台输出的SQL语句
hibernate.hbm2ddl.auto当SessionFactory创建时是否根据映射文件自动验证表结构或自动创建、自动更新数据库表结构。该参数的取值为:validate、update、create和create-drop。
hibernate.connection.autocommit事务是否自动提交

2.Hibernate中API介绍

public static void save(Customer c){
    //加载主配置文件(hibernate.cfg.xml)
    Configuration cfg = new Configuration().configure();
    //创建SessionFactory对象
    SessionFactory factory = cfg.buildSessionFactory();
    //使用SessionFactory生产一个Session
    Session session=factory.openSession();
    //开启事务
    Transaction tx=session.beginTransaction();
    //保存客户
    session.save(c);
    //提交事务
    tx.commit();
    //释放资源
    session.close();
    factory.close();
}
2.1 Configuration对象

1.作用

  • 在使用Hibernate时,首先要创建Configuration实例,Configuration实例主要用于启动、加载、管理hibernate的配置文件信息。
  • 在启动Hibernate的过程中,Configuration实例首先确定Hibernate配置文件的位置,然后读取相关配置,最后创建一个唯一的SessionFactory实例。Configuration对象只存在于系统的初始化阶段,它将SessionFactory创建完成后,就完成了自己的使命。
  • Hibernate通常使用Configuration config = new Configuration().configure();的方式创建实例,此种方式默认会去src下读取 hibernate.cfg.xml配置文件。如果不想使用默认的hibernate.cfg.xml配置文件,而是使用指定目录下(或自定义)的配置文件,则需要向configure()方法中传递一个文件路径的参数,其代码写法如下:Configuration config = new Configuration().configure(“xml文件位置”);
  • 此种写法hibernate会去指定位置查找配置文件,例如,想要使用src下config包中的hibernate.cfg.xml文件,只需将文件位置加入configure()中即可,其代码如下所示:
    Configuration config = new Configuration().configure("/config/hibernate.cfg.xml");

【加载映射文件】
Hibernate除了可以使用Configuration对象加载核心配置文件以外,还可以利用该对象加载映射文件。因为如使用properties文件作为Hibernate的核心配置文件,其他的属性可以使用key=value的格式来设置,但是映射没有办法加载。这时这个对象就有了用武之地。可以在手动编写代码的时候去加载映射文件。

Configuration configuration = new Configuration().configure("xml文件位置");
configuration.addResource("cn/itcast/domain/Customer.hbm.xml");

2.常用方法
默认构造函数:Configuration config = new Configuration();
它只能加载类的根路径下,名称为hibernate.properties的配置文件。不能加载xml

  • configure():它用于加载类的根路径下,名称为hibernate.cfg.xml的配置文件
  • buildSessionFactory():根据配置文件,构建SessionFactory
  • addResource(String url):指定映射文件的位置
  • addClass(Class clazz):指定实体类的字节码

2.2 SessionFactory对象

1.作用
SessionFactory接口负责Hibernate的初始化和建立Session对象。它在Hibernate中起到一个缓冲区作用,Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。

SessionFactory 实例是通过Configuration对象获取的,其获取方法如下所示。
SessionFactory sessionFactory = config.buildSessionFactory();

2.常用方法
今天只给大家介绍一个方法:(其它方法后面再讲解)
openSession():每次都是生成一个新的Session

3.注意细节
SessionFactory对象维护了很多信息:

  • Hibernate主配置文件中的基本配置
  • 映射文件的位置,以及映射文件中的配置
  • 映射文件所对应表的一些预定义的SQL语句(这些语句都是通用的) 比如:全字段保存,根据id的全字段更新,根据id的全字段查询,根据id的删除等等。
    注意:每个映射文件(实体)都有自己的预定义SQL语句
  • hibernate的二级缓存
    同时,它是一个线程安全的对象,所有由该工厂生产的Session都共享工厂中维护的数据。

4.使用原则
由于SessionFactory维护了很多信息同时又是线程安全的,一般情况下,一个项目中只需要一个SessionFactory,只有当应用中存在多个数据源时,才为每个数据源建立一个SessionFactory实例。因此,不应该反复的创建和销毁。
原则:一个应用应该只有一个SessionFactory。在应用加载时创建,应用卸载时销毁。

5.在Hibernate中使用数据源(连接池)
SessionFactory内部还维护了一个连接池,如果我们需要使用第三方的连接池如C3P0,那么需要我们自己手动进行配置

配置C3P0步骤如下:

  1. 在eclipse中导入连接池的jar包
    在这里插入图片描述
  2. 在hibernate主配置文件中配置
<?xml version="1.0" encoding="UTF-8"?>
<!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>  
  <!-- 1、连接数据库的基本信息 -->
	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
	<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
	<property name="hibernate.connection.username">root</property>
	<property name="hibernate.connection.password">root</property>
  <!-- 2、hibernate的基本配置 -->
	<!-- 数据库的方言 -->
	<propertyname="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
	<!-- 是否显示SQL语句 -->
	<property name="hibernate.show_sql">true</property>
	<!-- 是否格式化SQL语句 -->
	<property name="hibernate.format_sql">true</property>
	<!-- 配置数据源(连接池)的提供商 -->
     <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
  <!-- 3、映射文件的位置 -->
<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

测试:

@Test
public void test() {
	Session s = null;
	Transaction tx = null;
	try {
		s = HibernateUtil.openSession();// 获取Session对象
		//Work work=null;//Work是Hibernate中的一个接口对象(不能实例化)
		//s.doWork(Work对象);//doWork使用的是jdbc的connection对象执行原生的SQL语句
		//通过内部类的方式实现
		s.doWork(new org.hibernate.jdbc.Work() {
			@Override
			public void execute(Connection conn) throws SQLException {
				System.out.println(conn.getClass().getName());//输出连接对象
			}
		});
	} catch (Exception e) {
			e.printStackTrace();
	} finally {
			s.close();
	}
}

在这里插入图片描述


2.3 Session对象

1.作用
Session 是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,它的主要功能是为持久化对象提供创建、读取和删除的能力,所有持久化对象必须在session的管理下才可以进行持久化操作。

创建SessionFactory实例后,就可以通过它获取Session实例。获取Session实例有两种方式,一种是通过openSession()方法,另一种是通过getCurrentSession()方法。两种方法获取session的代码如下所示:

//采用openSession方法创建session
Session session = sessionFactory.openSession();
//采用getCurrentSession()方法创建session
Session session = sessionFactory.getCurrentSession();

以上两种获取session实例方式的主要区别是,采用openSession方法获取Session实例时,SessionFactory直接创建一个新的Session实例,并且在使用完成后需要调用close方法进行手动关闭。而getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭。

没有配置把Session绑定当前线程之前,getCurrentSession方法无法使用,所以今天我们只使用openSession方法。配置把Session绑定到线程的方式,我们下次课来讲解。

2.常用方法

  • save(Object entity):保存一个实体到数据库
  • update(Object entity):更新一个实体
  • delete(Object entity):删除一个实体
  • get(Class clazz,Serializable id):根据id查询一个实体。参数的含义:Class表示要查询的实体类字节码。Serializable就是查询
  • beginTransaction():开启事务,并返回事务对象

3.细节
由于SessionFactory已经维护了很多数据,所以Session就维护较少的内容。
Session是一个轻量级对象。并且:它不是线程安全的!!!!!!!
Session维护了hibernate的一级缓存(关于一级缓存的问题在下次课讲解)。
Session的反复创建销毁不会消耗太多资源。

4.使用原则
由于Session对象属于线程不安全,当一个线程有多个Session时,无法保证事务。所以一个线程要保障只有一个Session对象。


2.4 Transaction对象

1.作用
Transaction接口主要用于管理事务,它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,其开启方式如下所示。

Transaction transaction = session.beginTransaction();

2.常用方法

  • commit():提交事务
  • rollback():回滚事务

Session执行完数据库操作后,要使用Transaction接口的commit()方法进行事务提交,才能真正的将数据操作同步到数据库中。发生异常时,需要使用rollback()方法进行事务回滚,以避免数据发生错误。因此,在持久化操作后,必须调用Transaction接口的commit()方法和rollback()方法。


3.抽取HibernateUtil工具类

package cn.itcast.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
 * Hibernate的工具类: 
 * 		加载配置文件
 * 		根据配置文件创建一个SesseionFactory对象(只能创建一个)
 * 		提供相关方法,用来获取一个Session对象
 * 
 * @author Jackie
 */
public class HibernateUtil {
	private static SessionFactory factory;
	// 使用静态代码块获取SessionFactory
	static {
		//细节:Hibernate把所有可预见的异常,都转成了运行时异常(工具中不会提示要添加异常块)
		try {
			// 加载hibernate.cfg.xml配置文件
			Configuration config = new Configuration().configure();
			factory = config.buildSessionFactory();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 获取一个新的Session对象(每次都是一个新对象)
	 * @return
	 */
	public static Session openSession(){
		return factory.openSession();
	}
}

4.实现Hibernate查询、修改、删除

4.1 查询客户信息
public static void main(String[] args) {
    //创建客户类对象
    System.out.println(findOneById(96L));
}

public static Customer findOneById(Long id){
    Customer c =null;//接收查询出来的实体
    Session session = null;//Session对象
    Transaction tx = null ;//事务对象
    try{
        //使用Hibernate工具类获取Session对象
        session = HibernateUtil.openSession();
        //开启事务
        tx = session.beginTransaction();
        //根据ID查询客户信息
        c = session.get(Customer.class, id);
        //提交事务
        tx.commit();
    }catch(Exception e){
        tx.rollback();//事务回滚
        e.printStackTrace();
    }finally{
        session.close();//释放资源
    }
    return c;
}

注意:因为我们表中主键使用了bigint,而bigint对应的java类型为long类型,所以这里我们只能为long或Long

4.2 修改客户信息
public static void main(String[] args) {
    //创建客户类对象
    update(95L, "18626233484");
}

public static void update(Long id, String newPhone){
    Customer c =null;//接收查询出来的实体
    Session session = null;//Session对象
    Transaction tx = null ;//事务对象
    try{
        //使用Hibernate工具类获取Session对象
        session = HibernateUtil.openSession();
        //开启事务
        tx = session.beginTransaction();
        //根据ID查询客户信息
        c = session.get(Customer.class, id);
        // 修改客户
        c.setCustPhone(newPhone);
        session.update(c);
        //提交事务
        tx.commit();
    }catch(Exception e){
        tx.rollback();//事务回滚
        e.printStackTrace();
    }finally{
        session.close();//释放资源
    }
}
4.3 删除客户信息
public static void delete(Customer c){
    Session session = null;//Session对象
    Transaction tx = null ;//事务对象
    try{
        //使用Hibernate工具类获取Session对象
        session = HibernateUtil.openSession();
        //开启事务
        tx = session.beginTransaction();
        //根据ID查询客户信息
        session.delete(c);
        //提交事务
        tx.commit();
    }catch(Exception e){
        tx.rollback();//事务回滚
        e.printStackTrace();
    }finally{
        session.close();//释放资源
    }
}
删除直接创建的实体(不是通过查询获得实体对象)
@Test
public void testDelete2(){
	Session s=null;
	Transaction tx= null;
	try{
		Customer c = new Customer();
		c.setCustId(100L);//仅给实体对象中的id赋值(对应的是表中的主键)
		s=HibernateUtil.openSession();//获取Session对象
		tx=s.beginTransaction();//开启事务
		s.delete(c);//删除实体(实体对象中仅有id有值,其它属性为null)
		tx.commit();//提交事务
	}catch(Exception e){
		tx.rollback();//发生异常时,回滚事务
		e.printStackTrace();
	}finally{
		s.close();
	}
}

在这里插入图片描述
结论:实体对象中只要id有值,delete()就可以删除。(delete方法默认是根据主键删除)

4.4 实体查询的另一种方法load

1.实体查询的概念
所谓实体查询即OID(对象标识符/对象主健)查询,就是使用主键作为条件来查询一个实体。其中涉及的方法是Session对象get方法和load方法。

2.方法的说明
get方法

/**
 * 根据id查询一个实体
 * @param entityType 指的是要查询的实体类字节码对象
 * @param id 查询的条件,即主键的值。
 * @return 返回的是实体类对象
 */
<T> T get(Class<T> entityType, Serializable id);

/**
 * 需求: 使用get方法查询id为1的客户
 */
@Test
public void testGet(){
	Session s = HibernateUtil. getOpenSession();
	Transaction tx = s.beginTransaction();
	Customer c = s.get(Customer.class, 100L);
	tx.commit();
	System.out.println(c);
}

load方法

/**
 * 根据id查询一个实体
 * @param theClass 指的是要查询的实体类字节码
 * @param id查询的条件,即主键的值。
 * @return 返回的是实体类对象或者是实体类对象的代理对象
 */
<T> T load(Class<T> theClass, Serializable id);

/**
 * 需求: 使用load方法查询id为1的客户
 */
@Test
public void testLoad(){
	Session s = HibernateUtil.getOpenSession();
	Transaction tx = s.beginTransaction();
	Customer c = s.load(Customer.class, 100L);
	tx.commit();
    System.out.println(c);
}

问题:既然两个方法都是根据ID查询一个实体,他们有什么区别呢?

3.get和load 的区别

1.查询的时机不一样

  • get方法任何时候都是立即加载,即只要一调用get马上发起数据库查询
  • load方法默认情况下是延迟加载,即真正用到对象的非OID字段数据才发起查询
    load方法可以通过配置的方式改为立即加载。

配置的方式:

// 由于load方法是hibernate的方法所以只有XML的方式:
<class name="Customer" table="cst_customer" lazy="false">

2.返回的结果不一样

  • get方法永远返回查询的实体类对象。
  • load方法当是延迟加载时,返回的是实体类的代理对象。

涉及的概念:

  • 立即加载:

    是不管用不用马上查询。

  • 延迟加载:

    等到用的时候才真正发起查询。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值