1. Hibernate优缺点
1.1. 优点
1.1.1. 简化操作数据库数据的代码
1.1.2. 可移植性好,兼容所有主流数据库
1.2. 缺点
1.2.1. 由于数据库操作封装程度高,系统会生成辅助的SQL语句,从而会牺牲整个程序的性能
2. Hibernate基本配置步骤
2.1. 添加jar包
2.2. 配置hibernate.cfg.xml
<!-- 数据库连接参数 -->
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="hibernate.connection.username">c##jack</property>
<property name="hibernate.connection.password">8888</property>
<!-- hibernate兼容当前数据库的方言类 -->
<property name="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</property>
<!-- 在控制台显示SQL语句,并格式化 -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
2.3. 创建实体类
2.4. 配置实体映射文件Xxx.hbm.xml
<!-- package 指定类所在的包名 -->
<hibernate-mapping package="com.entity">
<!-- class 针对类做的属性名与列名的映射关系
name="Emp" 类名
-->
<class name="Emp" table="emp">
<!-- id 主键映射
name="empid" 属性名
column="empid" 列名
-->
<id name="empid" column="empid">
<!-- generator 主键生成策略 -->
<generator class="sequence">
<!-- 指定生成主键值的序列名 -->
<param name="sequence_name">seq_emp</param>
</generator>
</id>
<!-- 非主键映射
无论属性名与列名是否一致,都需要逐一配置映射
-->
<property name="ename" column="ename"/>
<property name="job" column="job"/>
<property name="hiredate" column="hiredate"/>
<property name="sal" column="sal"/>
<property name="comm" column="comm"/>
<property name="deptid" column="deptid"/>
</class>
</hibernate-mapping>
2.5. 编写测试类
Configuration cfg;
// 创建SessionFactory对象
SessionFactory sf;
// 创建Session对象
Session session;
//创建事务对象
Transaction tx;
// 根据配置文件创建配置对象
cfg = new Configuration().configure();
// 创建SessionFactory对象
sf = cfg.buildSessionFactory();
// 创建Session对象
session = sf.openSession();
// 创建事务对象(增删改操作需要手动提交事务)
tx=session.beginTransaction();
//根据对象的主键属性值查找一行记录
Emp emp = session.get(Emp.class, 56);
System.out.println(emp);
2.6. Hibernate进行增删改操作
2.6.1. 如果新增操作,直接构建对象,调用session.save()方法
2.6.2. 如果删除操作,构建对象,对象必须包含主键属性,调用session.delete()
2.6.3. 如果没有主键值,删除则报错
2.6.4. 如果修改操作,构建对象,对象必须包含数据表存在的记录的主键,调用session.update()
2.6.5. 如果使用硬编码方式创建的对象,有部分属性没有赋值,则hibernate自动视为这些属性值需要赋值为空
2.6.6. 推荐做修改操作时,首先使用session查询出该对象,然后根据业务需求,修改部分属性的值,调用tx.commit(),hibernate可以自动更新数据库对应的记录
3. Hibernate对象的三种状态
对象处于持久化状态,可以通过改变对象的属性值,并手动提交,则数据库对应的记录会及时更新
4. HQL
4.1. 基本概念:Hibernate Query language
4.2. 基本语句:select 属性名1,属性名2,... from 类名
4.3. Hibernate5.2版之后语法有改动
4.3.1. 导入hibernate查询包:org.hibernate.query.Query;
4.4. 使用Query对象查找数据
//from ... 表示默认获取所有列
String hql="from Emp where ename like '%刘%'";
Query q= session.createQuery(hql);
//如果获取的数据是多行多列,并且每一列都与类的属性做了映射
List<Emp> emps= q.list();
4.5. 绑定参数
//根据占位符绑定参数
//setParameter方法不支持自动类型转换,
//给参数赋值一定要与对应的属性类型完全一致
String hql="from Emp where ename like ? and sal>=? and sal<=?";
Query<Emp> q= session.createQuery(hql);
q.setParameter(0, "%刘%");
q.setParameter(1, 5000d);
q.setParameter(2, 10000d);
//根据名称绑定参数
String hql="from Emp where ename like :n and sal>=:min and sal<=:max";
Query<Emp> q= session.createQuery(hql);
q.setParameter("n", "%刘%");
q.setParameter("min", 5000d);
q.setParameter("max", 10000d);
4.6. 使用HQL多条件查询
4.6.1. 根据条件来拼接HQL语句
String sql="from Emp where 1=1 ";
if (eu.getName()!=null&&!eu.getName().equals("")) {
sql+="and ename like :name ";
}
4.6.2. HQL语句中使用名称绑定参数
4.6.3. 定义帮助类,将用户输入的条件封装成对象
EmpUtil eu=new EmpUtil();
eu.setName("%j%");
//hibernate可以根据条件对象的属性,自动将同名的参数赋值到HQL语句上
Query<Emp> q= session.createQuery(sql);
q.setProperties(eu);
4.7. 使用HQL分页
4.7.1. 指定查询结果从第几个索引号开始显示(默认索引号为0):
q.setFirstResult((pageIndex-1)*pageSize);
4.7.2. 指定每次获取的数据行数:
q.setMaxResults(pageSize);
4.8. 接受单行数据的方法:uniqueResult()
5. HQL投影查询
5.1. 如果需要查询表的部分列
//Emp类必须有ename,hiredate,sal三个参数的构造方法
select new Emp(ename,hiredate,sal) from Emp
5.2. 如果查询结果与实体类属性不一致
5.2.1. 多行多列:select deptid,count(1) from Emp group by deptid
返回数据的类型:List<Object[]>
5.2.2. 单行单列:select count(1) from Emp
返回数据的类型:Object
5.2.3. 单行多列:select deptid,count(1) from Emp where deptid=1 group by deptid
返回数据的类型:Object[]
6. Criteria
6.1. 基本语法
// 指定查询的目标数据表对应的实体类信息
Criteria c = session.createCriteria(Emp.class);
List<Emp> emps = c.list();
6.2. 追加条件语句
Criterion cr = Restrictions.ilike("ename", "j", MatchMode.ANYWHERE);
Criterion cr2 = Restrictions.between("sal", 5000d, 10000d);
List<Integer> ids = new ArrayList<Integer>();
ids.add(50);
ids.add(51);
ids.add(52);
Criterion cr3 = Restrictions.in("empid", ids);
// 将条件对象添加到Criteria对象中
c.add(cr);
c.add(cr2);
c.add(cr3);
所有创建Criterion 条件对象添加到Criteria 对象中,默认是以and关键字连接
6.3. 使用Criterion 拼写带有or关键字的SQL语句
criteria.add(
Restrictions.or(
Restrictions.eq("ename", "刘德华"),
Restrictions.le("sal", 8000d)
)
);
6.4. 多添加查询:根据条件非空的判断,调用对应的追加where子句的方法
if (eu.getName() != null && !eu.getName().equals("")) {
c.add(Restrictions.ilike("ename", eu.getName(), MatchMode.ANYWHERE));
}
6.5. 分页
int pageIndex = 1;
int pageSize = 5;
c.setMaxResults(pageSize);
c.setFirstResult(pageSize * (pageIndex - 1));
6.6. 投影查询
//创建投影列表
ProjectionList pl=Projections.projectionList();
//将需要显示的列使用Property.forName()方法添加到投影列表中
pl.add(Property.forName("ename"));
pl.add(Property.forName("sal"));
//将投影列表添加到Criteria对象中
c.setProjection(pl);
//查询结果的数据类型是List<Object[]>
List<Object[]> objs = c.list();
for (Object[] obj : objs) {
System.out.println(obj[0]+"--"+obj[1]);
}
//相当于count(ename)
pl.add(Projections.count("ename"));
//group by deptid
pl.add(Projections.groupProperty("deptid"));
7. 原生SQL查询
String sql="select deptid,max(sal),min(sal),ROUND(avg(sal),2) from emp group by deptid";
SQLQuery q= session.createSQLQuery(sql);
List<Object[]> objs = q.list();
for (Object[] obj : objs) {
System.out.println(obj[0]+"--"+obj[1]+"--"+obj[2]+"--"+obj[3]);
}