一、查询详解
参考:https://mp.weixin.qq.com/s/8roKUxjEQOOcK38dRVq_eQ
1.1 主键查询
作用:通过主键来查询数据库的记录,从而返回一个JavaBean对象。
1.1.1 get()立即查询
User user = (User)session.get(User.class,2);
1.1.2 load()懒加载查询
User user = (User)session.load(User.class,2);
1.1.3 对象导航查询
需求:查询部门信息时,直接可以获取到雇员信息,不需要二次查询。
SQL查询时:若想要得到当前对象与另一对象的关联关系时,就必须用多表查询来得到数据。
Hibernate提供了对象导航查询:可以使用主键查询完之后,得到的对象,直接使用对象得到集合…就可以得到对应的数据了。
// 对象导航查询
Dept dept = (Dept) session.get(Dept.class, 12);
System.out.println(dept.getDeptName());
//这里就可以得到部门对应的所有员工
System.out.println(dept.getEmps());
1.2 HQL查询
HQL:hibernate query language。hibernate提供的面向对象的查询语言。
——查询的是对象以及对象的属性。
——因此区分大小写!
1.2.1 查询全部列
//方式一:直接写对象
String hql1 = "from Dept";
//方式二:可以为对象取别名
String hql2 = "select d from Dept d";
// 注意:HQL不支持*号。
// String hql3 = "select * from Dept d";
Query q = session.createQuery(hql1);
Query q = session.createQuery(hql2);
1.2.2 查询指定的列
使用HQL查询指定的列,返回的是对象数组Object[]。
缺点:不易操作。
//只查询name和eatBanana列
String hql = "select m.name,m.eatBanana from Monkey m";
Query q = session.createQuery(hql);
优化:封装对象。Hibernate还提供了将对象数组封装成对象的功能
// JavaBean要有对应的构造函数
String hql = "select new Monkey(m.name,m.eatBanana) from Monkey m";
Query q = session.createQuery(hql);
1.2.3 条件查询
占位符——?
String hql = "from Monkey m where m.name = ?";
Query query = session.createQuery(hql);
//HQL是从0开始的
query.setParameter(0, "大猴子");
命名参数——:命名
String hql = "from Monkey m where m.name = :monkeyName";
Query query = session.createQuery(hql);
query.setParameter("monkeyName", "大猴子");
范围查询——between and
String hql = "from Dept d where deptId between ? and ?";
Query query = session.createQuery(hql);
query.setParameter(0, 1);
query.setParameter(1, 20);
模糊查询——Like
String hql = "from Dept d where deptName like ?";
Query query = session.createQuery(hql);
// 注意:%号要写在参数上,不能写带SQL上!
query..setString(0, "%部%");
1.2.4 聚合函数统计
HQL提供了uniqueResult()这么一个方法,返回只有一条记录的数据。
String hql = "select COUNT(*) from Monkey";
Query query = session.createQuery(hql);
Object o = query.uniqueResult();
System.out.println(o);
1.2.5 分组查询
String hql = "select e.dept, count(*) from Employee e group by e.dept";
Query query = session.createQuery(hql);
1.2.6 连接查询
种类:
——内连接【等值连接】
——左外连接
——有外链接
注意:连接查询返回的也是对象数组!
// 1) 内连接 【映射已经配置好了关系,关联的时候,直接写对象的属性即可】
String hql1 = "from Dept d inner join d.emps";
// 2) 左外连接
String hql2 = "from Dept d left join d.emps";
// 3) 右外连接
String hql3 = "from Employee e right join e.dept";
Query query = session.createQuery(hql);
优化:迫切连接。
目的:使在返回的时候是一个对象、而不是对象数组!
// 1) 迫切内连接 【使用fetch, 会把右表的数据,填充到左表对象中!】
String hql1 = "from Dept d inner join fetch d.emps";
// 2) 迫切左外连接
String hql2 = "from Dept d left join fetch d.emps";
// 3) 迫切右外连接
String hql3 = "from Employee e right join fetch e.dept";
Query query = session.createQuery(hql);
1.2.7 命名查询
查询语句放在配置文件中。
含义:
1、在具体的映射配置文件中存放一些常用的语句,并命名。
2、在程序中,可以获取配置文件配置的语句。
<!-- 存放sql语句,如果有<>这样的字符数据,需要使用CDATA转义! -->
<query name="getAllDept">
<![CDATA[ from Dept d where deptId < ? ]]>
</query>
String hql = "getAllDept";
Query query = session.createQuery(hql);
query.setParameter(0, 10);
1.3 QBC查询
QBC查询: query by criteria 。 完全面向对象的查询。
Criteria使用的是add()来添加条件。条件又使用一个Restrictions类来封装。
// 创建Criteria对象
Criteria criteria = session.createCriteria(User.class);
// 添加条件。
criteria.add(Restrictions.eq("id",1));
// 查询全部数据
List<User> list = criteria.list();
Criteria查询就使用不了分组、连接查询了。
1.4 本地SQL查询
提出问题:当表的结构十分复杂时,若使用关联映射,则配置文件是十分臃肿的。因此,并不是所有数据表都使用映射的方式来创建。
解决问题:用SQLQuery来维护数据。
注意:
1、SQLQuery是不能跨数据库的,因为Hibernate在配置的时候就指定了数据库的“方言”。
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM monkey_ limit 0,3");
System.out.println(sqlQuery.list());
2、返回的也是对象数组。
3、Hibernate也支持在SQLQuery中对数据进行对象封装。只要添加类型就行了。
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM monkey_ limit 0,3").addEntity(Monkey.class);
System.out.println(sqlQuery.list());
1.5 分页查询
1.5.1 传统方式
步骤:
1、得到数据库表中的总记录数。
2、查询起始位置到末尾位数的数据
1.5.2 Hibernate方式
Query query = session.createQuery("from Monkey");
// 得到滚动结果集
ScrollableResults scroll = query.scroll();
//滚动到最后一行
scroll.last();
int totalSize = scroll.getRowNumber() + 1; // 总记录数。
/*
* String hql = "SELECT COUNT(*) FROM Monkey";
* Long totalSize = (Long) query.uniqueResult();
*/
//设置分页位置
query.setFirstResult(0); // 起始位置。
query.setMaxResults(3); // 查询结果最大记录数
System.out.println(query.list());
二、Hibernate连接池
Hibernate自带了连接池,该连接池比较简单。而Hibernate又对C3P0这个连接池支持,因此常更换Hibernate连接池为C3P0。
2.1 查看Hibernate自带的连接池
可以通过Hibernate.properties文件中查看Hibernate默认配置的连接池。
hibernate.properties的配置文件可以在\project\etc找到。
Hibernate的自带连接池啥都没有,就一个连接数量为1。
2.2 查看Hibernate对C3P0的支持
#hibernate.c3p0.max_size 2 最大连接数
#hibernate.c3p0.min_size 2 最小连接数
#hibernate.c3p0.timeout 5000 超时时间
#hibernate.c3p0.max_statements 100 最大执行的命令的个数
#hibernate.c3p0.idle_test_period 3000 空闲测试时间
#hibernate.c3p0.acquire_increment 2 连接不够用的时候, 每次增加的连接数
#hibernate.c3p0.validate false
2.3 修改Hibernate连接池
在hibernate.cfg.xml中配置C3p0,让C30P0作为Hibernate的数据库连接池。
查找Hibernate支持的连接池组件有什么:
在hibernate.cfg.xml中配置对应的类就和相关配置。
<!-- 【连接池配置】 -->
<!-- 配置连接驱动管理类 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 配置连接池参数信息 -->
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.max_size">4</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.idle_test_period">30000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
三、线程Session使用
创建Session方法 | 含义 |
---|---|
openSession() | 每次都会创建新的Session |
getCurrentSession() | 获取当前线程的Session,如果没有则创建。 |
一般地,我们使用线程Session比较多,需要在配置文件中配置。
<!--配置线程Session-->
<property name="hibernate.current_session_context_class">thread</property>
//openSession: 创建Session, 每次都会创建一个新的session
public void testSession1() throws Exception {
Session session1 = sf.openSession();
Session session2 = sf.openSession();
System.out.println(session1 == session2);
session1.close();
session2.close();
}
// getCurrentSession 创建或者获取session。线程的方式创建session
public void testSession2() throws Exception {
// 一定要配置:<property name="hibernate.current_session_context_class">thread</property>
Session session3 = sf.getCurrentSession();// 创建session,绑定到线程
Session session4 = sf.getCurrentSession();// 从当前访问线程获取session
System.out.println(session3 == session4);
// 关闭 【以线程方式创建的session,可以不用关闭; 线程结束session自动关闭】
//session3.close();
//session4.close(); 报错,因为同一个session已经关闭了!
}
四、逆向工程
提出问题:由于我们每次编写Hibernate的时候都需要写实体,写映射文件。而且Hibernate的映射文件也容易出错。而逆向工程可以帮我们自动生成实体和映射文件,这样就非常方便了。
4.1 使用PowerDesigner
在设计数据库表时,我们使用PowerDesigner来生成概念模型\物理模。
设计一个人员组织架构:有机构、部门、员工、领导、角色、权限。
1、一个机构有多个部门
2、一个部门有多个员工
3、领导可以管理多个部门,同时领导他自己也是员工
4、一个员工可以有多个角色
5、一个角色可以分配给多个人
6、人员角色分配后可以设置是否有效,分配时间等
7、一个角色有多个权限
4.2 概念模型
在PowerDesigner中,箭头指向的方向永远是“一”的一方。
4.3 生成物理模型
4.4 生成sql语句
我们可以单个生成,一个一个复制。
也可以把整个物理模型的sql语句一起生成。