Hibernate01-基础

 


Hibernate01-基础

1.Hibernate入门程序

  1. 引入依赖。
<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>5.6.4.Final</version>
    </dependency>
</dependencies>
  1. hibernate.cfg.xml配置文件。
<?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>

        <!-- 数据库配置 -->
        <!-- 配置连接MySQL数据库连接的基本参数 -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/ke?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=true&amp;allowMultiQueries=true</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">123456</property>

        <!-- hibernate框架配置 -->
        <!-- 配置Hibernate的方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
        <!-- 输出执行的SQL -->
        <property name="hibernate.show_sql">true</property>
        <!-- SQL格式化 -->
        <property name="hibernate.format_sql">true</property>

        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 配置c3p0数据库连接池 -->
        <property name="hibernate.c3p0.min_size">10</property>
        <property name="hibernate.c3p0.max_size">20</property>
        <!-- 数据库连接池中的数量超过最大的数量后,没有超过最大的数量,每次向数据库申请2个连接。 -->
        <property name="hibernate.c3p0.acquire_increment">2</property>
        <!-- 超过最小的数量,空闲2秒后就会被回收。 -->
        <property name="hibernate.c3p0.timeout">2000</property>
        <!-- 每个两秒检查一次,是否有空闲的连接需要回收 -->
        <property name="hibernate.c3p0.idle_test_period">2000</property>
        <!-- 可以缓存的最大的statements数量。 -->
        <property name="hibernate.c3p0.max_statements">10</property>

        <!-- 这两个配置对Mysql是无效的,但是对Oracle是有效的 -->
        <!-- fetch_size,查询时每次数据库每次返回100条数据;batch_size,更新时每次更新30条数据。 -->
        <property name="hibernate.jdbc.fetch_size">100</property>
        <property name="hibernate.jdbc.batch_size">30</property>

        <!-- 关联数据库和实体类的映射文件 -->
        <mapping resource="mapping/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>
  1. 实体类和数据库表映射的配置文件。
<?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.my.hibernate01.pojo.User" table="tb_user">
        <!-- 建立类中的属性与表中的主键的映射 -->
        <id name="id" column="id">
            <!-- 主键的生成策略,使用数据库本地的方式生成id。 -->
            <generator class="native" />
        </id>

        <!-- 类中普通属性和表中的字段的映射 -->
        <property name="name" column="name" />

        <property name="age" column="age" />
    </class>
</hibernate-mapping>
  1. 实体类。
@Data
public class User {

    private int id;
    private String name;
    private int age;
}
  1. 插入数据的Hello World。
public class Test01 {

    private Session session;
    private Transaction transaction;
    private SessionFactory sessionFactory;

    @Test
    public void testHelloWorld() {
        User user = new User();
        user.setName("tom");
        user.setAge(10);

        session.save(user);
    }

    @Before
    public void before() {
        // 1 加载Hibernate的核心配置文件
        Configuration configuration = new Configuration().configure();

        // 2 创建SessionFactory对象,类似于JDBC中的连接池
        sessionFactory = configuration.buildSessionFactory();

        // 3 通过SessionFactory获取到Session对象,类似于JDBC中的Connection
        session = sessionFactory.openSession();

        // 4 开启事务
        transaction = session.beginTransaction();
    }

    @After
    public void after() {
        // 5 关闭事务
        transaction.commit();

        // 6 释放资源
        session.close();
        sessionFactory.close();
    }
}

2.hibernate核心配置文件hibernate.cfg.xml

  1. hibernate.hbm2ddl.auto配置。
<!-- 自动生成数据库表的策略。
        1 create,每次启动都会重新生成数据库表,会导致之前的数据丢失。
        2 create_drop,SessionFactory关闭就会将数据库表删除。
        3 update,没有对应的数据库表时,在进行创建。
        4 validate,会将数据库表和实体类进行比较,如果不同则抛出异常。
-->
<property name="hibernate.hbm2ddl.auto">update</property>

3.实体类和数据库表映射文件Xxx.hbm.xml

  1. 配置包名。
<hibernate-mapping package="com.my.hibernate01.pojo">
</hibernate-mapping>

4.hibernate核心类

  1. Configuration的作用是启动hibernate程序,加载hibernate.cfg.xml配置文件,通常情况下Configuration对象只有一个实例,即Configuration是单例的。

  2. SessionFactory接口的作用加载连接数据库,扩展参数,映射信息,通过这些映

    射信息创建Session对象,通常情况下SessionFactory也是单例的。

  3. Session接口提供CRUD方法来操作对象,从而操作数据库。Session是线程不安全的对象,在项目中可以创建多个Session对象,每个线程就创建一个Session对象。

  4. Transaction接口用于执行事务操作 。

  5. Query接口用于执行HQL查询。

  6. Criteria接口用于执行基于对象的查询(QBC查询)。

5.Session核心方法

  1. save(Object obj) ,保存对象。
  2. update(Object obj),更新对象。
  3. saveOrUpdate(Object obj),添加或修改对象。
  4. delete(Object obj),删除对象。
  5. get(Class clz,Serialize id),获取对象。
  6. load(Class clz,Serialize id),获取对象。和get获取对象的区别,load()延时加载,在对象使用时才从数据库查询数据。

6.hibernate主键策略

  1. identity,利用数据库的自增长,如Mysql的auto_increment。
  2. sequence,利用数据库序列生成的能力,例如Oracle的sequence。
  3. native,本地策略,由hibernate自动根据不同的数据选择最优策略。如Mysql选择identity;Oracle选择sequence。
  4. uuid,生成32位16进制的字符串,id需要是String类型。
  5. increment,生成数据库表递进的数值类型。会查询当前表中最大的id,select max(id) from tb_student,会有并发问题。
  6. assigned,由开发者在插入时填充主键。

7.对象关系映射-一对多

  1. 实例类。如果实体类使用@Data注解,会有循环加载的问题。
@Getter
@Setter
@ToString
public class Customer {

    private int id;
    private String name;

    @ToString.Exclude
    private Set<Order> orders = new HashSet<>();
}

@Getter
@Setter
@ToString
public class Order {

    private int id;
    private String orderName;

    @ToString.Exclude
    private Customer customer;
}
  1. Xxx.hbm.xml映射文件。
<hibernate-mapping>
    <class name="com.my.manyToOne.Customer" table="tb_customer">
        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="name" column="name" />

        <set name="orders" cascade="delete">
            <key column="customer_id" />
            <one-to-many class="com.my.manyToOne.Order" />
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.my.manyToOne.Order" table="tb_order">
        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="orderName" column="order_name" />

        <many-to-one name="customer" class="com.my.manyToOne.Customer" column="customer_id" />
    </class>
</hibernate-mapping>
  1. insert插入操作。
@Test
public void testManyToOneInsert() {
    Customer customer = new Customer();
    customer.setName("alice");

    Order order01 = new Order();
    order01.setOrderName("A002");

    Order order02 = new Order();
    order02.setOrderName("A002");

    order01.setCustomer(customer);
    order02.setCustomer(customer);

    session.save(customer);
    session.save(order01);
    session.save(order02);
}
  1. select查询操作。
@Test
public void testManyToOneGet() {
    Customer customer = session.get(Customer.class, 1);
    System.out.println(customer);

    // 延时加载,使用时进行数据库的查询。
    System.out.println(customer.getOrders());
}
  1. delete删除操作。

    1. 没有在Customer.hbm.xml中配置cascade="delete"。
    @Test
    public void testManyToOneDelete() {
        Customer customer = session.get(Customer.class, 7);
    
        // 1 没有在Customer.hbm.xml中配置cascade="delete",不会进行级联删除,
        // 删除有映射关系的数据,会进行两步操作。
        // 1) 将tb_order对应的customer_id设置为null。
        // 2) 删除tb_customer中对应的customer_id数据,不会删除tb_order对应的数据。
        session.delete(customer);
    }
    
    1. 在Customer.hbm.xml中配置cascade="delete"。
    @Test
    public void testManyToOneDelete() {
        Customer customer = session.get(Customer.class, 7);
    
        // 2 在Customer.hbm.xml的Set中配置cascade="delete"。
        // 1) 先查询到tb_custom关联的tb_order数据。
        // 2) 将tb_order的customer_id设置为null。
        // 3) 将tb_order对应的customer_id这条数据删除。
        // 4) 将删除tb_customer中的数据。
        session.delete(customer);
    }
    
    1. 在Customer.hbm.xml中配置cascade="delete" inverse="true"。
    @Test
    public void testManyToOneDelete() {
        Customer customer = session.get(Customer.class, 7);
    
        // 3 在Customer.hbm.xml的Set中配置cascade="delete" inverse="true",Customer放弃
        // 维护关系。
        // 1) 先查询到tb_custom关联的tb_order数据。
        // 2) 将tb_order对应的customer_id这条数据删除。
        // 3) 将删除tb_customer中的数据。
        session.delete(customer);
    }
    

8.cascade和inverse配置详解

  1. cascade,级联操作。级联保存,save-update;级联删除,delete;级联保存与删除:,all。
  2. inverse, 是否把关联关系的维护权反转。默认inverse=false。如果设置inverse=true,即当前方放弃关联关系的维护。通常在一对多的关联配置中,多方无法放弃关系维护权,建议放弃1方的维护权,在1方加上inverse=true配置。

9.对象关系映射-多对多

  1. 实体类。
@Getter
@Setter
@ToString
public class Person {

    private int id;
    private String name;

    private Set<Role> roles = new HashSet<>();
}

@Getter
@Setter
@ToString
public class Role {

    private int id;
    private String name;

    // 多对多映射在一方,排除toString()方法,防止循环查询。
    @ToString.Exclude
    private Set<Person> persons = new HashSet<>();
}
  1. xml配置文件。
<hibernate-mapping package="com.my.manyToMany">
    <class name="Person" table="tb_person">
        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="name" column="name" />

        <!-- 多对多的映射,table用于指定中间表 -->
        <set name="roles" table="tb_person_role">
            <!-- tb_person在中间表对应的外键 -->
            <key column="person_id" />
            <!-- tb_role对应的类和在中间表的外键。 -->
            <many-to-many class="Role" column="role_id" />
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.my.manyToMany.Role" table="tb_role">
        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="name" column="name" />

        <!-- 多对多的映射,table用于指定中间表 -->
        <set name="persons" table="tb_person_role" inverse="true">
            <!-- tb_role在中间表对应的外键 -->
            <key column="role_id" />
            <!-- tb_person对应的类和在中间表的外键。 -->
            <many-to-many class="com.my.manyToMany.Person" column="person_id" />
        </set>
    </class>
</hibernate-mapping>
  1. insert操作。
/**
     * 如果tb_person和tb_role都维护关联关系,就会在tb_person_role中添加重复的记录,两种解决方法。
     * 1) 代码中进行一方关系的维护,即只有一方使用Set.add()维护关系。
     * 2) 在tb_role中使用inverse="true",放弃关联关系的维护。
*/
@Test
public void manyToManySave() {
    Person p1 = new Person();
    p1.setName("tom");

    Person p2 = new Person();
    p2.setName("alice");

    Role role1 = new Role();
    role1.setName("超级管理员");

    Role role2 = new Role();
    role2.setName("管理员");

    // Person和Role都维护关联关系。
    p1.getRoles().add(role1);
    p1.getRoles().add(role2);
    p2.getRoles().add(role1);

    // 代码中Role放弃关联关系的维护。
    //role1.getPersons().add(p1);
    //role1.getPersons().add(p2);
    //role2.getPersons().add(p1);

    session.save(p1);
    session.save(p2);
    session.save(role1);
    session.save(role2);
}
  1. select操作。
@Test
public void manyToManySelect() {
    Person person = session.get(Person.class, 1);

    System.out.println(person.getRoles());
}
  1. delete操作。
@Test
public void manyToManyDelete() {
    Person person = new Person();
    person.setId(1);

    // tb_person中配置cascade="all",级联删除,会进行两步操作。
    // 1) 删除中间表tb_person_role的记录。
    // 2) 删除tb_person中的数据,不会删除tb_role中的数据。
    session.delete(person);
}

10.对象关系映射-一对一

  1. 一对一的两种实现方式。

    1. 外键关联映射,给外键添加唯一约束,用于一对一的映射,会有一个单独的列最为外键进行唯一映射。
    2. 主键关联映射。使用id列映射另一个表的id列。
  2. 外键关联映射。

    1. 实体类。
    @Getter
    @Setter
    @ToString
    public class Student {
    
        private int id;
        private String name;
    
        private Card card;
    }
    
    @Getter
    @Setter
    public class Card {
    
        private int id;
        private String cardNo;
    
        @ToString.Exclude
        private Student student;
    }
    
    1. xml映射关系。
    <hibernate-mapping package="com.my.ontToOne">
        <class name="Student" table="tb_student">
            <id name="id" column="id">
                <generator class="native" />
            </id>
    
            <property name="name" column="name" />
    
            <one-to-one name="card" class="Card" />
        </class>
    </hibernate-mapping>
    
    <hibernate-mapping package="com.my.ontToOne">
        <class name="Card" table="tb_card">
            <id name="id" column="id">
                <generator class="native" />
            </id>
    
            <property name="cardNo" column="card_no" />
    
            <!-- 外键映射,配置unique="true"后,这个外键就是唯一的。 -->
            <many-to-one name="student" column="student_id" class="Student" unique="true" />
        </class>
    </hibernate-mapping>操作。
    
    1. insert操作。
    @Test
    public void oneToOneSave() {
        Student student = new Student();
        student.setName("alice");
    
        Card card = new Card();
        card.setCardNo("0002");
    
        card.setStudent(student);
    
        session.save(student);
        session.save(card);
    }
    
  3. 主键关联映射,只需要修改Card的xml配置文件。

<hibernate-mapping package="com.my.ontToOne">
    <class name="Card" table="tb_card">
        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="cardNo" column="card_no" />

        <!-- 主键关联映射,constrained="true",表示主键关联映射,
            tb_card的id会使用tb_student的id,从而进行主键关联。 -->
        <one-to-one name="student" class="Student" constrained="true" />
    </class>
</hibernate-mapping>
posted @   行稳致远方  阅读(33)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示