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查询
- HQL,Hibernate Query Language,Hibernate 查询语言。语法和SQL语法类似。
- 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查询
- QBC,Query By Criteria,使用Criteria对象进行查询。
- 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查询
- 本地SQL查询,相当与直接写SQL进行查询。
- 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对象的三种状态。
- 临时状态。没有OID,并且没有被Session管理。
- 持久化状态。有OID,被Session管理。
- 游离状态。有OID,但是没有被Session管理。
- 代码实现。
@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一级缓存和快照机制
- hibernate的Session中有两个区域,一级缓存区和快照数据保存的区域。
- 在hibernate事务提交时,会执行flush()方法,对比一级缓存的数据和快照数据的区别,如果有区别就会向数据库发送SQL更新数据。所以hibernate保存在Session中的持久化对象可以更改数据库。
- 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延时加载
- 类级别的延时加载。
/**
* 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);
}
- 关联级别的延时加载。
/**
* 关联查询的延时加载。
* 关闭一方的延时加载。<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抓取策略
- 抓取策略,通过SQL的合并减少和数据库的交互查询。如将关联查询的多次查询,修改为join查询。
- 一方抓取策略的三种配置,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());
}
- 多方抓取策略的两种配置,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连接池
- 导入依赖。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.6.4.Final</version>
</dependency>
- 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>
- 测试类。
@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二级缓存配置
- 引入eheache依赖。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.6.7.Final</version>
</dependency>
- 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" />
- 测试代码。
@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
- hibernate.cfg.xml中添加配置。
<!-- 使用ThreadLocal管理Session -->
<property name="hibernate.current_session_context_class">thread</property>
- 修改通过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();
}