HQL简介
HQL(Hibernate Query Language)描写对象操作的一种查询语言,Hibernate特有HQL的语法和SQL语法基本一致,不同的是HQL是面向对象的查询,查询的是对象和对象中的属性,HQL的关键字不区分大小写,但类名和属性区分大小写
语法示例
- SELECT 别名/属性名/表达式
- FROM 实体AS别名
- WHERE 过滤条件
- HAVING 分组后的结果的查询条件
- ORDER BY 排序条件
查询案例
投影查询
不能把结果封装成对象,如果强制转换会报java.lang.ClassCastException异常错误
List<Object[]> list = (List<Object[]>) session.createQuery("select s.id,s.username from Student s").list();
for (int i = 0; i < list.size(); i++) {
Object[] objs = list.get(i);
for (int j = 0; j < objs.length; j++) {
System.out.println("------------------");
Object obj = objs[j];
System.out.println(obj);
}
}
排序查询(desc降序、asc升序)
List<Object[]> list = (List<Object[]>) session.createQuery("select s.id,s.username from Student s order by s.id desc").list();
for (int i = 0; i < list.size(); i++) {
Object[] objs = list.get(i);
for (int j = 0; j < objs.length; j++) {
System.out.println("------------------");
Object obj = objs[j];
System.out.println(obj);
}
}
聚合函数和分组查询
- 聚合函数,总记录数 注意返回的结果是long类型
Query query = session.createQuery("select count(*) FROM Student");
long count = (long) query.uniqueResult();
System.out.println(count);
- 平均数
Query query = session.createQuery("select avg(s.id) FROM Student s");
double avg = (double) query.uniqueResult();
System.out.println(avg);
- 分组
Query query = session.createQuery("select o.customer,count(o) from Order o group by Customer having count (o) > 2");
List<Object[]> list = query.list();
for (int i = 0; i < list.size(); i++) {
Object[] objs = list.get(i);
System.out.println("-------------------------------");
for (int j = 0; j < objs.length; j++) {
System.out.println(objs[j]);
}
System.out.println("-------------------------------");
}
image.png
连接查询
INNER JOIN 在表中存在至少一个匹配时,INNER JOIN关键字返回行 LEFT OUT JOIN 关键字会从左表(table-name)返回所有的行即便右表(table-name)中没有匹配的行
RIGHT OUTER JOIN:关键字会在右表(table-name)返回所有的行,即使在左表(table-name)中没有匹配到行
image.png
隐式内连接,等效SQL隐式内连接
Query query = session.createQuery("from Customer c,Order o where c = o.customer");
List<Object[]> list = query.list();
for (int i = 0; i < list.size(); i++) {
Object[] objs = list.get(i);
System.out.println("----------------------");
for (int j = 0; j < objs.length; j++) {
Object obj = objs[j];
System.out.println(obj);
}
}
System.out.println(query.list());
内连接
List<Object[]> list = session.createQuery("from Customer c inner join c.orders").list();
for (int i = 0; i < list.size(); i++) {
System.out.println("---------------------");
Object[] objects = list.get(i);
for (int j = 0; j < objects.length; j++) {
Object obj = objects[j];
System.out.println(obj);
}
}
迫切内连接
List<Customer> customers = session.createQuery("from Customer c inner join fetch c.orders").list();
for (int i = 0; i < customers.size(); i++) {
System.out.println("---------------");
Customer customer = customers.get(i);
if (customer.getOrders().size() == 0) {
System.out.println(customer);
}else{
Iterator<Order> iterator = customer.getOrders().iterator();
while (iterator.hasNext()) {
Order order = iterator.next();
System.out.println(customer +":" + order);
}
}
}
案例8,命名查询把HQL写在映射文件的query标签
- HQL语句写在Java文件中,有时候不灵活,如果要修改语句,要重新编译项目打包
- 我们可以在*hbm.xml中命名查询语句,然后Java会从hbm.xml取出hql语句,这样之后开发,可以直接找hbm.xml进行配置
把HQL写在映射文件中比较灵活,HQL写入映射文件有两种方式
第一种:写在类Class标签里面,HQL是局部【name赋值前面要加包名+类名】
Customer.hbm.xml
<class name="Customer" table="t_customer">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<set name="orders" inverse="false" cascade="save-update,delete" batch-size="2">
<key column="customer_id"></key>
<one-to-many class="Order"></one-to-many>
</set>
<query name="hql1">from Customer</query>
</class>
代码示例: 查询语句【包名+类名+查询name的赋值】
Query query = session.getNamedQuery("com.zzx.hibernate.domain.Customer.hql1");
List<Customer> list = query.list();
for (int i = 0; i < list.size(); i++) {
System.out.println("--------------");
Iterator<Order> iterator = list.get(i).getOrders().iterator();
while (iterator.hasNext()) {
Order order = iterator.next();
System.out.println(list.get(i) + ":" +order);
}
}
第二种:写在hibernate-mapping的标签,HQL是全局的
Customer.hbm.xml
<hibernate-mapping package="com.zzx.hibernate.domain">
<class name="Customer" table="t_customer">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<set name="orders" inverse="false" cascade="save-update,delete" batch-size="2">
<key column="customer_id"></key>
<one-to-many class="Order"></one-to-many>
</set>
</class>
<query name="hql1">from Customer where name=?</query>
</hibernate-mapping>
代码示例:查询语句直接写入hbm.xml query标签name的赋值即可
Query query = session.getNamedQuery("hql1");
query.setParameter(0,"鲁智深");
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer.getName()+":" + customer.getOrders());
QBC查询
关于QBC查询,Hibernate系列章节一有讲QBC查询链接
离线查询
Detached Criteria离线查询对象,不需要使用session就可以拼凑查询条件,一般使用在web层或service层拼凑,将此对象传递给DAO层,此时将与Session进行绑定执行查询
DetachedCriteria dc = DetachedCriteria.forClass(Order.class);
dc.add(Restrictions.ge("id",2));
Criteria criteria = dc.getExecutableCriteria(session);
List<Order> orders = criteria.list();
for (Order order : orders) {
System.out.println("-------------------");
System.out.println(order);
}
Hibernate的常见配置
整合C3P0连接池
第一步导入C3P0 Jar包工程
默认Hibernate提供的框架中有C3P0包
第二步:配置C3P0 查找Hibernate.properties
<property name="hibernate.c3p0.max_size">2</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.timeout">500</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
事务的隔离级别
- 原子性:整体【原子性是指事务包含的所有操作要么全部成功,要么全部失败】
- 一致性:数据【一个事务执行之前和执行之后都必须处于一致性状态】
- 隔离性:并发【对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到其他事务在并发的执行】
- 持久性:结果【持久性是指一个事务一旦被提交了,要么对数据库中的数据的改变是永久性的】
隔离问题
- 脏读:一个事务读到另外一个事务未提交的内容【读取提交的内容】,在读隔离级别,所有事务都可以看到其他未提交事务的执行结果,本隔离级别很少用于实际应用,因为它的性能也比不了其他的级别
- 不可重复读:一个事务读到另外一个已经提交的内容(insert)【读取提交内容】这个大多数数据库系统默认隔离级别(但不是MYSQL默认的)它满足了隔离的简单定义,一个事务只能看见已经提交事务所作的改变
- 虚读(幻读):一个事务读到另外一个已经提交的事务的内容(update)这个MYSQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取的问题,幻读,简单的说,幻读指当用户读取某一些范围的数据行时,另一个事务又在该范围内插入一行新的行,当用户再读取该范围的数据行时,才会发现新的幻读行
- Serializable (可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读的问题,简言之,它是在每个读的数据行上加入共享锁,在这个级别,可能导致大量的超时现象和锁竞争
read uncommitld 读未提交,存在三个问题
read committed 读已提交,解决,脏读存在两个问题
Serializable 串行化,单事务,没有问题
Hibernate中设置隔离级别
<property name="hibernate.connection.isolation">4</property>
网友评论