Hibernate-基础学习

一、概括

是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。

二、入门

1、poem.xml 引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.chen</groupId>
    <artifactId>hibernate</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.10.Final</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>
</project>

2、配置文件:hibernate.cfg.xml

<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- hibernate- configuration是连接配置文件的根元素 -->
<hibernate-configuration>
    <session-factory>
        <!--数据源配置-->
        <property name="connection.username">root</property>
        <property name="connection.password">chenguangwei</property>
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8</property>

        <!-- C3P0数据连接池 -->
        <property name="hibernate.c3p0.acquire_increment">10</property>
        <property name="hibernate.c3p0.idle_test_period">10000</property>
        <property name="hibernate.c3p0.timeout">5000</property>
        <property name="hibernate.c3p0.max_size">30</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_statements">10</property>

        <!-- 数据库方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 打印SQL -->
        <property name="show_sql">true</property>

        <!-- 格式化SQL语句 -->
        <property name="format_sql">true</property>

        <!-- 是否自动生成生成数据表 -->
        <property name="hibernate.hbm2ddl.auto">create</property>
    </session-factory>
</hibernate-configuration>

3、创建实体类

@Data
public class Customer {
    private Integer id;
    private Set<Orders> orders;
}
@Data
public class Orders {
    private Integer id;
    //订单名
    private String name;
    private Customer customer;
}

4、创建实体关系映射文件
实体:

@Data
public class People {

    private Integer id;
    private String name;
    private Double money;
}

映射文件:

<?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>
    <!-- 建立类与表的映射 -->
    <class name="com.chen.entity.People" table="people">
        <!-- 建立类中的属性与表中的主键对应 -->
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="identity"/>
        </id>
        <!-- 建立类中的普通的属性和表的字段的对应 -->
        <property name="name" type="java.lang.String">
            <column name="name"></column>
        </property>
        <property name="money" type="java.lang.Double" column="money" />
    </class>
</hibernate-mapping>

5、实体关系映射文件注册到Hibernate的配置文件中

<!-- 注册实体关系映射文件 -->
<mapping resource="com/chen/entity/People.hbm.xml"></mapping>

执行测试方法往数据库表中插入数据:

public class Test {
    public static void main(String[] args) {
        //创建Configuratiin
        Configuration configuration = new Configuration().configure();
        //获取SessionFactory
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取Session
        Session session = sessionFactory.openSession();
        People people = new People();
        people.setName("小Y");
        people.setMoney(100.05);
        session.save(people);
        session.beginTransaction().commit();
    }
}

报错:Exception in thread "main" org.hibernate.boot.MappingNotFoundException: Mapping (RESOURCE) not found : com/chen/entity/People.hbm.xml : origin(com/chen/entity/People.hbm.xml) at org.hibernate.boot.spi.XmlMappingBinderAccess.bind(XmlMappingBinderAccess.java:56) at org.hibernate.boot.MetadataSources.addResource(MetadataSources.java:294) at org.hibernate.boot.cfgxml.spi.MappingReference.apply(MappingReference.java:70) at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:468) at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:84) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724) at com.chen.test.Test.main(Test.java:13)
无法读取到xxx.xml资源文件:需要在poem.xml中配置resource

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

又报错:java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'type=MyISAM'
原因是hibernate配置文件中开启自动生成数据表的原因,索性直接把它关了,手动去数据库建一个people表:
在这里插入图片描述
运行成功:在这里插入图片描述
查询数据库,数据存在:
在这里插入图片描述

6、Hibernate级联操作
(1)一对多关系
客户和订单:每个客户可以购买多个产品,生成多个订单,但是每一个订单只属于一个客户,所以:客户->订单=1->多
A、数据库是通过主外键实现:1为主表,多为从表(添加外键)。
例:
a.创建表

CREATE TABLE customer(
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);
CREATE TABLE orders(
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    cid INT(11),
    PRIMARY KEY(id),
    CONSTRAINT `FK_CID_CUSTOMER_ID` FOREIGN KEY (cid) REFERENCES customer(id)
);

B、面向对象中通过以下方式实现一对多关系。
例:
a.创建实体类

@Data
public class Customer {
    private Integer id;
    private String name;
    //一个Customer对应多个orders
    private Set<Orders> orders;
}
@Data
public class Orders {
    private Integer id;
    private String name;
    //一个Order对应一个Customer
    private Customer customer;
}

b.创建映射文件
Customer.hbm.xml:

<?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>
<!-- 建立类与表的映射 -->
<class name="com.chen.entity.Customer" table="customer">
    <!-- 建立类中的属性与表中的主键对应 -->
    <id name="id" column="id" type="java.lang.Integer">
        <generator class="identity"/>
    </id>
    <!--建立类中的普通属性与表中属性对应-->
    <property name="name" type="java.lang.String">
        <column name="name"></column>
    </property>
    <!-- set标签用来配置实体类中的集合属性orders:table->表名  key->外键  one-to-many:集合泛型的实体类对象 -->
    <set name="orders" table="orders">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
    </set>
</class>
</hibernate-mapping>

Order.hbm.xml:

<?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>
<!-- 建立类与表的映射 -->
<class name="com.chen.entity.Orders" table="orders">
    <!-- 建立类中的属性与表中的主键对应 -->
    <id name="id" column="id" type="java.lang.Integer">
        <generator class="identity"/>
    </id>
    <!-- 建立类中的普通属性与表中属性对应 -->
    <property name="name" type="java.lang.String">
        <column name="name"></column>
    </property>
    <!-- 建立类中的类属性与表对应:name->属性名  class->属性对应的类  column->关联外键 -->
    <many-to-one name="customer" class="com.chen.entity.Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>

c.在Hibernate配置文件中注册映射文件

<mapping resource="com/chen/entity/Customer.hbm.xml"></mapping>
<mapping resource="com/chen/entity/Oreders.hbm.xml"></mapping>

d.通过Hibernate API去调用:

public class Test1 {
    public static void main(String[] args) {
        //创建Configuratiin
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        //获取SessionFactory
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取Session
        Session session = sessionFactory.openSession();

        //创建Customer对象
        Customer customer = new Customer();
        customer.setName("孟佳");

        //创建Oreders
        Orders orders = new Orders();
        orders.setName("订单H");

        //建立关系
        orders.setCustomer(customer);

        //保存
        session.save(customer);
        session.save(orders);
        //提交事务
        session.beginTransaction().commit();
    }
}

e.结果
控制台打印sql语句:
在这里插入图片描述
查询数据库:
在这里插入图片描述
在这里插入图片描述
(2)多对多关系
学生选课:一门课程可以被多个学生选择,一个学生可以选择多门课,所以:学生->课程=多->多
A、数据库是通过两个一对多关系来维护,学生和课程都是主表,额外增加一张中间表作为从表。
例:
创建数据库表

CREATE TABLE account(
    id INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);
CREATE TABLE course(
    id INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);
CREATE TABLE account_course(
    id INT(11) NOT NULL AUTO_INCREMENT,
    a_id INT(11),
    c_id INT(11),
    CONSTRAINT `FK_AID_ACCOUNT_ID` FOREIGN KEY (a_id) REFERENCES account(id),
    CONSTRAINT `FK_CID_COURSE_ID` FOREIGN KEY (c_id) REFERENCES course(id),
    PRIMARY KEY(id)
);

在这里插入图片描述
B、面向对象中通过以下方式实现多对多关系。
例:
a.创建实体类

@Data
public class Account {
    private Integer id;
    private String name;
    //一个学生可以选择多门课
    private Set<Course> courses;
}
@Data
public class Course {
    private Integer id;
    private String name;
    //一个课程可以被多人选择
    private Set<Account> accounts;
}

b.创建映射文件
Account.hbm.xml:

<?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>
<!-- 建立类与表的映射 -->
<class name="com.chen.entity.Account" table="account">
    <!-- 建立类中的属性与表中的主键对应 -->
    <id name="id" column="id" type="java.lang.Integer">
        <generator class="identity"/>
    </id>
    <!--建立类中的普通属性与表中属性对应-->
    <property name="name" type="java.lang.String">
        <column name="name"></column>
    </property>
    <!-- set标签用来配置实体类中的集合属性courses:table->中间表表名  key->当前类在中间表中的外键 -->
    <!-- many-to-many:多对多关系:class->指定courses属性对应的实体类  column->该实体类在中间表中的外键 -->
    <set name="courses" table="account_course">
        <key column="a_id"></key>
        <many-to-many class="com.chen.entity.Course" column="c_id"></many-to-many>
    </set>
</class>
</hibernate-mapping>

Course.hbm.xml:

<?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>
<!-- 建立类与表的映射 -->
<class name="com.chen.entity.Course" table="course">
    <!-- 建立类中的属性与表中的主键对应 -->
    <id name="id" column="id" type="java.lang.Integer">
        <generator class="identity"/>
    </id>
    <!--建立类中的普通属性与表中属性对应-->
    <property name="name" type="java.lang.String">
        <column name="name"></column>
    </property>
    <!-- set标签用来配置实体类中的集合属性courses:table->中间表表名  key->当前类在中间表中的外键 -->
    <!-- many-to-many:多对多关系:class->指定accounts属性对应的实体类  column->该实体类在中间表中的外键 -->
    <set name="accounts" table="account_course">
        <key column="c_id"></key>
        <many-to-many class="com.chen.entity.Account" column="a_id"></many-to-many>
    </set>
</class>
</hibernate-mapping>

c.在Hibernate配置文件中注册映射文件

<mapping resource="com/chen/entity/Account.hbm.xml"></mapping>
<mapping resource="com/chen/entity/Customer.hbm.xml"></mapping>

d.通过Hibernate API去调用:

public class Test2 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        //创建course对象
        Course course = new Course();
        course.setName("大学物理");
        //创建account对象
        Account account = new Account();
        account.setName("胡帅");
        //建立关系
        /*Set<Account> accounts = new HashSet<Account>();
        accounts.add(account);
        course.setAccounts(accounts);*/
        Set<Course> courses = new HashSet<Course>();
        courses.add(course);
        account.setCourses(courses);
        //保存
        session.save(course);
        session.save(account);
        //提交事务
        session.beginTransaction().commit();
        session.close();
    }
}

e.结果
在这里插入图片描述
可以从控制台打印SQL语句看出Hibernate把我们建立的关系通过sql语句的形式插入到中间表里(很智能!)。
补:
Java和数据库对于两种关系的体现完全是两种不同的方式,Hibernate框架的作用就是将这两种方式进行转换和映射

7、Hibernate延迟加载:也称为惰性加载或懒加载
1)提高程序的运行效率
众所周知:Java程序与数据库交互的频次越低,程序的运行效率就越高。为了尽量减少两者之间交互次数,Hibernate延迟加载应运而生。

2)诞生背景
客户和订单:当我们查询客户对象时,因为有级联设置,所以会将对应的订单信息一并查出来,这样就需要发送两条sql语句(两次交互),分别查询客户信息和订单信息。
延迟加载的思路:当我们查询客户的时候,如果不涉及订单数据,只发送一条sql语句(一次交互)查询客户信息;如果涉及订单数据,才会发送两条sql(两次交互)。
延迟加载可以看作是一种优化机制,根据需求不同,自动选择要执行的sql语句条数(交互次数)。

3)应用场景
(1)一对多关系(沿用之前Customer和ordes的例子)

A、查询Customer, 对Oredes进行延迟加载设置。在customer.hbm.xml进行设置,延时加载默认是开启的(lazy="true")。

<set name="orders" table="orders" lazy="true">
	<key column="cid"></key>
    <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

a、只查询Customer信息,不涉及Oreders(需要注意的是当调用toString()方法的时候,需要对原实体类@Data注解进行切换,否则会造成内存溢出错误,因为toString()方法中设计Oredes数据,程序会发送sql去查询orders数据,而orders对象打印有需要customer数据,两者之间造成循环调用):

@Getter
@Setter
public class Customer {
    private Integer id;
    private String name;
    private Set<Orders> orders;

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
@Setter
@Getter
public class Orders {
    private Integer id;
    private String name;
    private Customer customer;

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Test3 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Customer customer = session.get(Customer.class,10);
        System.out.println(customer.toString());
        session.close();
    }
}

控制台只打印一条sql语句:
在这里插入图片描述
b、当查询Customer设计orders属性时:
控制台打印了两条sql语句:
在这里插入图片描述
这就是延时加载,Hibernate会根据需求来选择sql语句的条数。

B、查询Customer,不对Oredes进行延迟加载设置。在customer.hbm.xml进行设置,将延时加载关闭(lazy="flase")。

<set name="orders" table="orders" lazy="false">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

a、查询Customer不涉及oredes级联属性:

public class Test3 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Customer customer = session.get(Customer.class,10);
        System.out.println(customer);
        session.close();
    }
}

控制台打印了两条sql语句,病没有根据需求来选择与数据库的交互次数:
在这里插入图片描述
C、lazy="extra",extra是比true更加懒惰(智能)的一种加载方式:
a、查询Customer对象,打印该对象对应的orders集合的长度(设置lazy="true"

<!--set标签lazy默认为true-->
<set name="orders" table="orders" lazy="true">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

执行:

public class Test3 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Customer customer = session.get(Customer.class,10);
        System.out.println(customer.getOrders().size());
        session.close();
    }
}

控制台打印:
在这里插入图片描述
其原理:从orders表中查询出符合条件的数据分别封装成Orders对象,然后把这些对象加到集合里面,然后再调用Customer的setter方法把这个集合赋值给orders属性,然后在调用集合的size()方法打印结果。因为此处只是单纯的想知道长度而无需知道orders具体属性是什么,所以有点浪费资源。
b、相同的目的(设置lazy="extra"

<set name="orders" table="orders" lazy="extra">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

控制台打印:
在这里插入图片描述
可以看出此时查询数据直接用count(id)查询符合条件的条数,更加高效。
C、查询Orders,对Customer选择进行延迟加载与否。在Orders.hbm.xml进行配置lazy的值:
在这里插入图片描述
< many-to-one>的lazy值:
默认情况下为false:表示关闭延时加载
no-proxy:当调用方法需要访问customer的成员变量时,发送SQL语句查询Customer,否则不查询。
proxy:无论调用方法是否需要访问customer的成员变量,都会发送SQL语句查询Customer。

(2)多对多关系(沿用之前Account和Course的例子,跟上面相同为了避免循环调用导致内存溢出,将@Data注解换为@Setter和@Getter,并重写toString()发法)
A、查询Course,加载对应的Account,在Course.hbm.xml中配置。默认延迟加载为开启的:

<set name="accounts" table="account_course" lazy="true">
        <key column="c_id"></key>
        <many-to-many class="com.chen.entity.Account" column="a_id"></many-to-many>
</set>

a、根据id查询Course不涉及Account:

public class Test4 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Course course = session.get(Course.class,2);
        System.out.println(course);
        session.close();
    }
}

打印结果:
在这里插入图片描述
b、根据id查询Course涉及Account:

public class Test4 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Course course = session.get(Course.class,2);
        System.out.println(course.getAccounts());
        session.close();
    }
}

控制台打印:
在这里插入图片描述
可已看出发送了两条SQL语句,跟前面一对多中标签是否开启懒加载原理相同,开启之后就能够根据需求来判断是否能够减少数据交互次数。同理设置lazy="extra"Hibrenate会更加高效,包括通过Account查询Course,原理都相同不再赘述。

8、Hibernate配置文件详解
(1)hibernate.cfg.xml:配置Hibernate的全局环境
A、数据库的基本信息。
B、集成C3p0,设置数据库连接池信息。
C、Hibernate基本信息

		<!-- 数据库方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 打印SQL -->
        <property name="show_sql">true</property>
        <!-- 格式化SQL语句 -->
        <property name="format_sql">true</property>
        <!--是否自动生成生成数据表
			update:动态创建表,如果表存在直接使用;否则则创建
			create:无论是否存在都创建,存在则先删除
			create-drop:初始化创建表,程序结束时删除表
			validate:校验实体关系映射文件和数据表是否对应,不对应直接报错
		-->
        <property name="hibernate.hbm2ddl.auto"></property>

D、注册映射文件

<mapping resource="com/chen/entity/People.hbm.xml"></mapping>

(2)XXXX.hbm.xml:实体关系映射文件:XXXX表示实体类名
例如:

<?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>
<!-- 建立类与表的映射 -->
<class name="com.chen.entity.Account" table="account">
    <!-- 建立类中的属性与表中的主键对应 -->
    <id name="id" column="id" type="java.lang.Integer">
        <generator class="identity"/>
    </id>
    <!--建立类中的普通属性与表中属性对应-->
    <property name="name" type="java.lang.String">
        <column name="name"></column>
    </property>
    <!-- set标签用来配置实体类中的集合属性courses:table->中间表表名  key->当前类在中间表中的外键 -->
    <!-- many-to-many:多对多关系:class->指定courses属性对应的实体类  column->该实体类在中间表中的外键 -->
    <set name="courses" table="account_course">
        <key column="a_id"></key>
        <many-to-many class="com.chen.entity.Course" column="c_id"></many-to-many>
    </set>
</class>
</hibernate-mapping>

A、 < hibernate-mapping>的属性:在这里插入图片描述
auto-import:指定我们是否可以在查询语句中使用非全限定类名,默认为true。如果项目中有两个同名的持久化类,最好在这两个类对应的映射文件中设置为false。
catalog:数据库catalog的名称。
default-access:Hibernate用来访问属性的策略。
default-lazy:指定未明确注明lazy属性的Java属性和集合类,Hibernate会采用什么样的加载风格,默认为true。
default-cascade:默认的级联关系,默认为none。
schema:数据库schema的名称。
·package·:给class节点对应的实体类统一设置包名。此处设置了包名,class节点的就可以name属性就可以省略包名。
B、 < hibernate-mapping>子标签< class>的属性:
name:实体类名。
table:数据表名。
schema:数据库schema的名称,会覆盖hibernate-mapping的schema。
catalog:数据库catalog的名称,会覆盖hibernate-mapping的catalog。
proxy:指定一个接口,在延时加载时作为代理使用。
dynamic-update:动态更新。
dynamic-insert:动态添加(默认为false)。
where:查询时给SQL添加where条件。
例:什么叫做动态添加(更新)?

public class Test5 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        People people = new People();
        people.setName("唐雅文");
        session.save(people);
        session.beginTransaction().commit();
        session.close();
    }
}

我们只是为People的name属性设了值,money属性并未设置,执行main、方法控制台打印:在这里插入图片描述

查询数据库:在这里插入图片描述
发现程序执行插入的时候为money加入了个null,而这个操作数据库同样可以完成,所以无需java程序为字段插入一个空置。引入动态添加:

<class name="com.chen.entity.People" table="people" dynamic-insert="true">

再次执行插入:在这里插入图片描述
此次只是插入了name字段属性,查询数据库,效果与之前一样,但是动态加载可以忽略为空字段的加入操作:在这里插入图片描述
C、< class>子标签< id>的属性:
name:实体类的属性名。
type:实体类属性数据类型。

  • 此处可以设置两种类型的数据:Java数据类型huozhe或者Hibernate映射类型。
  • 实体类的属性数据类型必须与数据表对应的字段数据类型一致:int对int、String对varchar等
  • 如何进行映射?
    java数据类型——>Hibernate映射类型——>SQL数据类型

column:数据表的主键字段名。
generator:主键生成策略。

  • hilo算法
  • increment:Hibernate自增
  • identity:数据库自增
  • native:本地策略,根据底层数据库自动选择主键的生成策略
  • uuid.hex算法
  • select算法

C、< class>子标签< property>的属性:
name:实体类的属性名。
column:数据表的字段名。
type:数据类型。
update:该字段是否可以修改(默认为true)。
insert·:该字段是否可以添加(默认为true)。
lazy:延时加载策略

D、 < set>标签属性inverse:用来解决双向维护
Customer和Orders是一对多关系,一个Customer对应多个Oreders,实体类中用一个set集合来表示对应的Oreders。
Customer.hbm.xml中使用set标签来配置映射关系。

/**
 * 双向维护问题
 *  例如Custoemr和Orders:
 *      Customer.hbm.xml中维护一对多关系
 *      Orders.hbm.xml中维护多对一关系
 */
public class Test6 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        //创建Customer对象
        Customer customer = new Customer();
        customer.setName("柯凡勾");
        //创建Orders对象
        Orders oreders = new Orders();
        oreders.setName("订单I");
        //创建第二个Orders对象
        Orders orders1 = new Orders();
        orders1.setName("订单J");
        //Orders维护关系
        oreders.setCustomer(customer);
        orders1.setCustomer(customer);
        //Customer维护关系
        Set<Orders> ordersSet = new HashSet<Orders>();
        ordersSet.add(oreders);
        ordersSet.add(orders1);
        customer.setOrders(ordersSet);
        //保存
        session.save(oreders);
        session.save(orders1);
        session.save(customer);
        //提交
        session.beginTransaction().commit();
        session.close();
    }
}

执行控制台打印:
在这里插入图片描述在这里插入图片描述

可以看出当开始根据关系往表中插入数据之后,又进行了两次次更新操作。因为Customer和Orders都在维护这个一对多关系,所以会重复设置主外键约束关系。
如何避免这种情况呢?

  • 在Java代码中去掉一方维护关系代码
  • 通过改变hbm.xml配置文件解决(设置inverse="true")
<set name="orders" table="orders" lazy="extra" inverse="true">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

控制台打印结果,只进行了三次插入,没有后续更新操作,所以双向维护问题得到了解决:
在这里插入图片描述
注:inverse属性是用来设置是否将维护权交给对方,默认为false:不交出维护权,双方都在维护。

E、 < set>标签属性cascade:用来设置级联操作

public class Test7 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Customer customer = session.get(Customer.class,19);
        session.delete(customer);
        session.beginTransaction().commit();
        session.close();
    }
}

执行控制台报错:
在这里插入图片描述
当通过以上方式删除一个Customer时,因为Orders通过外键关联到Customer表,直接从Customer删除数据需遵循先删子表再删主表原则
解决方式1:先删子表(Oreders)数据,再删主表数据

public class Test7 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Customer customer = session.get(Customer.class,19);
        Iterator<Orders> ordersIterator = customer.getOrders().iterator();
        while(ordersIterator.hasNext()){
            session.delete(ordersIterator.next());
        }
        session.delete(customer);
        session.beginTransaction().commit();
        session.close();
    }
}

解决方式2:在实体映射文件中设置cascade值完成级联删除

<set name="orders" table="orders" lazy="extra" inverse="true" cascade="delete">
        <key column="cid"></key>
        <one-to-many class="com.chen.entity.Orders"></one-to-many>
</set>

9、Hibernate-HQL

  • Hibernate Query Language,是Hibernate 框架提供的一种查询机制。他和SQL类似,不同的是HQL是面向对象的查询语句,让开发者能够以面向对象的思想来编写查询语句,对Java编程是一种友好的方式。
  • HQL不能直接参与数据库的交互,属于中间层语言:Java——》HQL——》Hibernate——》SQL——》DB
  • HQL只能完成查询、修改和删除,不支持新增。

(1)普通查询
查询表中所有数据,自动完成对象的封装,返回List集合。
HQL进行查询,from关键字后面不能写表名,必须写表对应的实体类名。

public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String hql = "from People";
        Query query = session.createQuery(hql);
        List<People> list = query.list();
        for(People people:list){
            System.out.println(people);
        }
        session.beginTransaction().commit();
        session.close();
    }
}

(2)分页查询

  • HQL分页查询可以通过query的方法来完成。
    A、setFirstResult():设置起始下标
    B、setMaxResults():设置截取长度
    从下标为1开始查询,总共查询3条:
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        String hql = "from People";
        Query query = session.createQuery(hql);
        query.setFirstResult(1);
        query.setMaxResults(3);
        List<People> list = query.list();
        for(People people:list){
            System.out.println(people);
        }
        session.beginTransaction().commit();
        session.close();
    }
}

数据库表数据:在这里插入图片描述
控制台打印分页查询结果:在这里插入图片描述
(3)where条件查询

  • HQL直接追加where关键字作为查询条件,与SQL没有区别。
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String hql = "from People where id =8";
        Query query = session.createQuery(hql);
        People people = (People) query.list().get(0);
        System.out.println(people);

        session.beginTransaction().commit();
        session.close();
    }
}

补:
People people = (People) query.list().get(0);返回一个集合,此时集合只有一个对象,通过下标0取出该对象。此方法当查询的id不存在时会报异常。
如果使用People people = (People)query.uniqueResult();当查询条件不存在时不会报异常会返回一个null。

(4)模糊查询

  • 查询名字中带有‘a‘的所有记录:
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String hql = "from People where name like '%a%'";
        Query query = session.createQuery(hql);
        List<People> list = query.list();
        for(People people:list){
            System.out.println(people);
        }

        session.beginTransaction().commit();
        session.close();
    }
}

查询结果:在这里插入图片描述
(5)order by排序

  • 按照‘money’列排序(默认为升序):
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        
        String hql = "from People order by money";
        Query query = session.createQuery(hql);
        List<People> list = query.list();
        for(People people:list){
            System.out.println(people);
        }

        session.beginTransaction().commit();
        session.close();
    }
}

控制台查询结果:在这里插入图片描述
补:
升序:String hql = "from People order by money asc";
降序:String hql = "from People order by money desc";

(6)查询实体对象的属性

  • 只查询People的那么属性:
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        
        String hql = "select name from People where id=9";
        Query query = session.createQuery(hql);
        String name = (String) query.uniqueResult();
        System.out.println(name);
        
        session.beginTransaction().commit();
        session.close();
    }
}

控制台查询结果:在这里插入图片描述
(7)占位符

  • 占位符使用
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String hql = "from People where name = :name";
        Query query = session.createQuery(hql);
        query.setString("name","李白");
        List<People> list = query.list();
        for(People people:list){
            System.out.println(people);
        }

        session.beginTransaction().commit();
        session.close();
    }
}

控制台打印结果:在这里插入图片描述
(8)级联查询:以Orders和Customer为例

  • 查询用户名为‘小阳’的用户所有订单
public class Test8 {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String hql = "from Customer where name = :name";
        Query query = session.createQuery(hql);
        query.setString("name","小阳");
        Customer customer = (Customer) query.uniqueResult();
        String hql1 = "from Orders where customer = :customer";
        Query query1 =session.createQuery(hql1);
        query1.setEntity("customer",customer);
        List<Orders> list = query1.list();
        for(Orders orders:list){
            System.out.println(orders);
        }

        session.beginTransaction().commit();
        session.close();
    }
}

控制台打印结果:在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值