Hibernate02-基础

Hibernate02-基础

1.基本查询-get和load

@Test
public void baseQueryForLoad() {
    // load(),延时加载
    Customer customer = session.load(Customer.class, 8);

    System.out.println(customer.getOrders());
}

@Test
public void baseQueryForGet() {
    Customer customer = session.get(Customer.class, 8);

    System.out.println(customer.getOrders());
}

2.HQL查询

  1. HQL,Hibernate Query Language,Hibernate 查询语言。语法和SQL语法类似。
  2. Java代码。主要分为单表查询和多表查询。
/**
 * HQL常用查询,单表查询。
 * 1) 全表查询
 * 2) 别名查询
 * 3) 条件查询
 * 4) 具名查询
 * 5) 分页查询
 * 6) 排序查询
 * 7) 聚合查询
 * 8) 投影查询
 *
 * HQL常用查询,多表查询。
 * 1) inner join 内连接查询
 * 2) left join 左连接查询
 * 3) right join 右连接查询
 */
public class HQLTest {

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

    @Test
    public void query09() {
        // 内连接查询,查询Customer类的客户名称和Order类的订单名称。
        // 左连接查询和右连接查询只是替换inner join
        Query query = session.createQuery("select c.name,o.orderName from Customer c inner join c.orders o");
        List<Object[]> orders = query.list();

        for (Object[] order : orders) {
            for (Object o : order) {
                System.out.print(o + "\t");
            }
            System.out.println();
        }
    }

    @Test
    public void query08() {
        // 投影查询,查询指定的字段,投影查询的结果是多个字段的数字
        Query query = session.createQuery("select id,orderName from Order");
        List<Object[]> orders = query.list();

        for (Object[] order : orders) {
            for (Object o : order) {
                System.out.print(o + "\t");
            }
            System.out.println();
        }

        // 将投影查询的结果封装为对象。
        // 1) HQL中的new Order需要指定报名,否则无法识别。
        // 2) Order类需要有指定字段的构造函数,否则无法创建对象。
        Query<Order> orderQuery = session.createQuery("select new com.my.manyToOne.Order(orderName) from Order", Order.class);
        List<Order> list = orderQuery.list();
        for (Order order : list) {
            System.out.println(order);
        }
    }

    @Test
    public void query07() {
        // 聚合查询,聚合函数的使用。
        Query<Long> query = session.createQuery("select count(*) from Order", Long.class);

        // 获取结果的方式一
        List<Long> counts = query.list();
        System.out.println(counts.get(0));

        // 获取结果的方式二,直接获取唯一结果
        Long result = query.uniqueResult();
        System.out.println(result);
    }

    @Test
    public void query06() {
        // 排序查询,id降序排列
        Query<Order> query = session.createQuery("from Order order by id desc", Order.class);

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @Test
    public void query05() {
        // 分页查询
        Query<Order> query = session.createQuery("from Order", Order.class);
        // 设置开始位置,相当与limit 0,2
        query.setFirstResult(0);
        // 设置每页的大小
        query.setMaxResults(2);

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @Test
    public void query04() {
        // 具名查询,给查询条件的参数设置名称。
        Query<Order> query = session.createQuery("from Order where orderName = :orderName", Order.class);
        query.setParameter("orderName", "A002");

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @Test
    public void query03() {
        // 条件查询
        //Query<Order> query = session.createQuery("from Order where orderName = 'A002'", Order.class);

        // 条件查询,SQL预编译。
        Query<Order> query = session.createQuery("from Order where orderName = ?1", Order.class);
        query.setParameter(1, "A002");

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @Test
    public void query02() {
        // 别名查询,多表查询时经常使用别名
        Query<Order> query = session.createQuery("select o from Order o", Order.class);

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @Test
    public void query01() {
        // 全表查询,查询表中的所有数据
        Query<Order> query = session.createQuery("from Order", Order.class);

        List<Order> orders = query.list();
        for (Order order : orders) {
            System.out.println(order);
        }
    }

    @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();
    }
}

3.QBC查询

  1. QBC,Query By Criteria,使用Criteria对象进行查询。
  2. Java代码。
/**
 * QBC Query By Criteria,使用Criteria对象进行查询。
 * Criteria查询已经过时,文件建议使用JAP。
 * @deprecated (since 5.2) for Session, use the JPA Criteria
 * 1) 全表查询
 * 2) 条件查询
 * 3) 分页查询
 * 4) 排序查询
 * 5) 聚合查询
 * 6) 投影查询
 */
public class QBCTest {

    @Test
    public void query06() {
        // Criteria投影查询。
        Criteria criteria = session.createCriteria(Customer.class);

        ProjectionList projectionList = Projections.projectionList();
        // 查询特定的字段
        projectionList.add(Property.forName("id"));
        projectionList.add(Property.forName("name"));

        criteria.setProjection(projectionList);

        List<Object[]> list = criteria.list();
        for (Object[] orders : list) {
            for (Object o : orders) {
                System.out.print(o + "\t");
            }
            System.out.println();
        }
    }

    @Test
    public void query05() {
        // Criteria聚合查询。
        Criteria criteria = session.createCriteria(Customer.class);
        // select count(id) from tb_order
        criteria.setProjection(Projections.count("id"));

        Long result = (Long) criteria.uniqueResult();
        System.out.println(result);
    }

    @Test
    public void query04() {
        // Criteria排序查询。
        Criteria criteria = session.createCriteria(Customer.class);
        // id降序排列
        criteria.addOrder(org.hibernate.criterion.Order.desc("id"));

        List<Customer> list = criteria.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    @Test
    public void query03() {
        // Criteria分页查询。
        Criteria criteria = session.createCriteria(Customer.class);
        criteria.setFirstResult(0);
        criteria.setMaxResults(1);

        List<Customer> list = criteria.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    @Test
    public void query02() {
        // Criteria条件查询。
        Criteria criteria = session.createCriteria(Customer.class);

        // 相当与 where name = 'alice' or name = 'tom'
        criteria.add(Restrictions.or(Restrictions.eq("name", "alice"),
                Restrictions.eq("name", "tom")));

        List<Customer> list = criteria.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

    @Test
    public void query01() {
        // Criteria全表查询。
        Criteria criteria = session.createCriteria(Customer.class);
        List<Customer> list = criteria.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
    }
}

4.本地SQL查询

  1. 本地SQL查询,相当与直接写SQL进行查询。
  2. Java代码。
public class SQLTest {

    @Test
    public void query02() {
        // 本地SQL查询,查询所有的数据,将查询结果封装为对象。
        NativeQuery sqlQuery = session.createSQLQuery("select * from tb_order");
        sqlQuery.addEntity(Order.class);
        List<Order> list = sqlQuery.list();

        for (Order order : list) {
            System.out.println(order);
        }
    }

    @Test
    public void query01() {
        // 本地SQL查询,查询所有的数据。
        NativeQuery sqlQuery = session.createSQLQuery("select * from tb_order");
        List<Object[]> list = sqlQuery.list();

        for (Object[] orders : list) {
            for (Object o : orders) {
                System.out.print(o + "\t");
            }
            System.out.println();
        }
    }
}

5.hibernate对象的三种状态。

  1. 临时状态。没有OID,并且没有被Session管理。
  2. 持久化状态。有OID,被Session管理。
  3. 游离状态。有OID,但是没有被Session管理。
  4. 代码实现。
@Test
public void test01() {
    Order order = new Order();
    order.setOrderName("A001");
    // 新创建的对象处于临时状态
    System.out.println(order);

    session.save(order);
    // save有处于持久化状态
    System.out.println(order);

    session.close();
    // session关闭处于游离状态
    System.out.println(order);
}

6.hibernate一级缓存和快照机制

  1. hibernate的Session中有两个区域,一级缓存区和快照数据保存的区域。
  2. 在hibernate事务提交时,会执行flush()方法,对比一级缓存的数据和快照数据的区别,如果有区别就会向数据库发送SQL更新数据。所以hibernate保存在Session中的持久化对象可以更改数据库。
  3. hibernate一级缓存的管理。清除一级缓存中的数据,即使对象发生了变化,事务提交时也不会进行数据库的修改。
@Test
public void test02() {
    Order order = session.get(Order.class, 1);
    order.setOrderName("ZZZ");

    // 如果没有清除一级缓存中的对象,对象发生了变化,事务提交时会进行数据库的修改。
    // 清除一级缓存中的数据后,即使对象发生了变化,也不会进行数据库的修改。
    // evict()清除一级缓存中的指定对象。
    session.evict(order);
    // clear()清除一级缓存中的全部对象。
    //session.clear();
    System.out.println(order);
}

7.hibernate延时加载

  1. 类级别的延时加载。
/**
     * load()延时加载。
     * 在Order.hbm.xml配置
     * <class name="com.my.manyToOne.Order" table="tb_order" lazy="false">
     * 关闭延时加载。
     */
@Test
public void test03() {
    Order order = session.load(Order.class, 1);
    // 此时还没有查询数据库,所以Order是代理类com.my.manyToOne.Order$HibernateProxy$UWAKCxKD
    System.out.println(order.getClass().getName());
    System.out.println(order);
}
  1. 关联级别的延时加载。
/**
     * 关联查询的延时加载。
     * 关闭一方的延时加载。<set name="orders" lazy="false">
     * 关闭多方的延时加载。<many-to-one lazy="false"  />
     */
@Test
public void test04() {
    Customer customer = session.get(Customer.class, 7);

    // 延时加载,在使用Order对象时才进行数据库的查询。
    System.out.println(customer.getOrders().size());
}

8.hibernate抓取策略

  1. 抓取策略,通过SQL的合并减少和数据库的交互查询。如将关联查询的多次查询,修改为join查询。
  2. 一方抓取策略的三种配置,select、join和subselect。
/**
     * 一方抓取策略。
     * fetch="select",如果有n个Customer客户,就是执行n+1条语句。1用于查询Customer,n次查询n个客户对应的Order数据。
     * fetch="subselect",执行一次查询,使用子查询的方式。
     * where custom_id in (select id from tb_custom)
     */
@Test
public void test06() {
    Query<Customer> query = session.createQuery("from Customer", Customer.class);
    List<Customer> customers = query.list();

    for (Customer customer : customers) {
        System.out.println(customer.getOrders());
    }
}

/**
     * hibernate抓取策略。
     * 在一方的Set标签中或者多方的many-to-one标签中配置抓取策略。
     * 一方抓取策略。
     * fetch="select",默认配置。会执行两条SQL,先查询Customer,在查询Order表。
     * fetch="join",执行一条SQL,直接通过left outer join查询出结果。
     */
@Test
public void test05() {
    Customer customer = session.get(Customer.class, 8);
    System.out.println(customer.getOrders());
}
  1. 多方抓取策略的两种配置,select和join。
/**
     * 多方抓取策略的配置。
     * <many-to-one fetch="select"  />
     * 1 多方抓取策略fetch有两个值,select和join。
     */
@Test
public void test07() {
    Order order = session.get(Order.class, 1);
    System.out.println(order.getCustomer());
}

9.hibernate配置c3p0连接池

  1. 导入依赖。
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-c3p0</artifactId>
    <version>5.6.4.Final</version>
</dependency>
  1. hibernate.cfg.xml中添加c3p0的配置。
<!-- 配置c3p0数据库连接池 -->
<!-- 配置使用c3p0的连接类 -->
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<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>
  1. 测试类。
@Test
public void test08() {
    session.doWork(connection -> {
        // 没有使用连接池输出 com.mysql.cj.jdbc.ConnectionImpl@5d43409a
        // 配置时候使用c3p0的连接池后输出,
        // com.mchange.v2.c3p0.impl.NewProxyConnection@4eed2acf
        System.out.println("====" + connection);
    });
}

10.hibernate二级缓存配置

  1. 引入eheache依赖。
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.6.7.Final</version>
</dependency>
  1. hibernate.cfg.xml中添加缓存的配置。
<!-- 二级缓存的配置 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

<!-- 配置使用二级缓存的类 -->
<class-cache class="com.my.manyToOne.Order" usage="read-only" />
  1. 测试代码。
@Test
public void cacheTest() {
    // 二级缓存测试
    Order order = session.get(Order.class, 1);
    System.out.println("======" + order);

    session.close();

    order = session.get(Order.class, 1);
    System.out.println("-----" + order);
}

11.hibernate隔离级别的配置

<!-- hibernate隔离级别的配置,有四种配置1、2、4和8
         1: read uncommited 2: read committed
         4: repeatable read 8: serializeable
         -->
<property name="hibernate.connection.isolation">1</property>

12.hibernate使用ThreadLocal管理Session

  1. hibernate.cfg.xml中添加配置。
 <!-- 使用ThreadLocal管理Session -->
<property name="hibernate.current_session_context_class">thread</property>
  1. 修改通过SessionFactory获取Session的方式。
@Test
public void test01() {
    // 获取当前线程的Session
    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    try {
        session.save(new Order());
        transaction.commit();
    }catch (Exception e) {
        transaction.rollback();
    }

    // 使用ThreadLocal管理Session后,Session自动关闭。
    //session.close();
}
posted @ 2022-04-10 08:07  行稳致远方  阅读(57)  评论(0)    收藏  举报