Hibernate 常用的数据库操作方法
1. 前言
本节课程聊聊如何使用 Session 完成基本数据操作。通过本课程,你将学习到:
- 如何实现查询;
- 如何实现保存和更新。
2. 基本数据操作方法
Session 中提供了很多方法,协助开发者快速完成基本的增加、删除、修改、查询(CRUD) 等基本数据操作。
2.1 查询
Session 提供了 2 个语义很明确的查询方法:
- get() 方法;
- load() 方法。
有选择,就会有比较。但,请先不用着急区分两者差异性,试着用用。
跑之前先学会走吗?
查询之前,可预先在表中多添加几条数据!避免池塘没鱼,捕不到鱼还不停怀疑自己,伤情绪。
get() 方法有很多重载,选择其中一个方法:
public Object get(Class clazz, Serializable id);
- 参数一: 指定待查询的 PO 对象的类型;
- 参数二: 指定一个实现 Serializable 接口的对象,充当查询条件,一般是主键。
编写 get() 方法的查询测试实例:
@Test
public void testGet() {
//会话对象
Session session = sessionFactory.openSession();
// 事务对象
Transaction transaction = null;
try {
// 打开事务
transaction = session.beginTransaction();
//查询学号为1的学生
Student stu=(Student)session.get(Student.class, new Integer(1));
assertEquals("男", stu.getStuSex());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
编写 load() 方法的查询测试实例:
@Test
public void testLoad() {
//会话对象
Session session = sessionFactory.openSession();
// 事务对象
Transaction transaction = null;
try {
// 打开事务
transaction = session.beginTransaction();
//查询学号为1的学生
Student stu=(Student)session.load(Student.class, new Integer(2));
assertEquals("男", stu.getStuSex());
transaction.commit();
} catch(Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
测试代码和上面没有很明显区别,结果也没有什么不同。
这两个方法从测试角度暂时无法区分,但本质上还是有很大区别。
2.2 更新、删除
添加数据的代码前面课程中已经使用多次,现在讨论更新、删除。更新、删除的前提条件:
- 更新、删除数据一定是数据库中的数据;
- 更新、删除包括一个前置操作,查询操作。
Session 提供了 public void delete(Object obj) 方法用来删除数据。
编写删除测试实例,先查询,再删除:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
//查询学号为1的学生
Student stu=(Student)session.load(Student.class, new Integer(1));
System.out.println(stu);
session.delete(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
运行后,结果很明显,数据库中数据被删除。
事务问题:
事务是一个较复杂的主题(后有专题课程),原生 JDBC 中,事务管理方式有:
- 数据库管理;
- JDBC API 管理。
Hibernate 提供了 Transaction 对象,用来对事务进行管理。
默认:autoCommit=false,意思是底层 JDBC 把事务交给 Hibernate 管理。
查询时,可以忽略事务。使用 Hibernate 进行增、删、改时。须显示调用 Transaction 的 commit() 或 rollback() 方法。
Session 提供了 public void update(Object object) 方法用于数据更新。
编写更新的测试代码:
@Test
public void testUpdate() {
//会话对象
Session session = sessionFactory.openSession();
// 事务对象
Transaction transaction = null;
try {
// 打开事务
transaction = session.beginTransaction();
//查询学号为1的学生
Student stu=(Student)session.load(Student.class, new Integer(1));
stu.setStuName("session同学");
session.update(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
结果没有什么意外,在程序中修改的数据通过 update() 方法同步到数据库。
如果查询 API 文档,会发现除了这些语义上很明确的方法外,还有其它几个方法
- public void saveOrUpdate(Object object);
- public Object merge(Object object);
- public void persist(Object object);
可以使用测试方式得到基本结论,如编写一个添加数据的实例时,使用 save、saveOrUpdate、persist 都可达到相同结果。
@Test
public void testAdd() {
Session session = sessionFactory.openSession();
// 事务对象
Transaction transaction = null;
try {
// 打开事务
transaction = session.beginTransaction();
//添加新学生
Student stu=new Student("慕课网", "男");
//可换成saveOrUpdate方法,save方法
session.persist(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
本节课,只从语义层面做区分,其内在差异性留到后续课程中慢慢揭晓,算是留下一个悬念。
休息一下,小结一下:
- Get()、Load()方法可用于查询;
- Save()可用于添加;
- Update()可用于更新数据;
- Delete()可用于删除;
- saveOrUpdate()有两重性,没有数据时添加数据,有数据时更新数据;
- persist()方法可用于更新、添加数据;
- merge()方法可用于更新、添加数据。
是不是有点上头了,心累呀!Hibernate 不地道呀,搞出这么多方法,这是要逼得有选择困难症的人哭,其实每一个方法都有特定的应用场景,Hibernate 总是体贴入微的想着为开发者解决每一种开发场景的需求。
记住刚开始说的,抓住主分支(知道层面),不管细节(内部机制层面)。
2.3 保存大对象
能不能把一张图片保存到数据库?
答案是明确的。
真实应用场景中不会这么做。
数据库中只会保存图片路径,具体的图片文件会存储在文件服务器中。
Hibernate 支持的大对象有:
- Clob:文本大对象;
- Blob:二进制数据大对象。
现在为每一个学生保存个人图片:
- student 类中添加 stuPic 属性(注意类型):
private Blob stuPic;
- 编写测试实例:
@Test
public void testInsertPic() {
//会话对象
Session session = sessionFactory.openSession();
// 事务对象
Transaction transaction = null;
try {
// 打开事务
transaction = session.beginTransaction();
//添加新学生
Student stu=new Student("MK", "男");
InputStream is=new FileInputStream("pic.png");
Blob stuPic=Hibernate.getLobCreator(session).createBlob(is, is.available());
stu.setStuPic(stuPic);
session.merge(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
如果要保存文本大对象,则使用如下代码:
Clob c=Hibernate.getLobCreator(session).createClob("我是中国人……");
执行结果,不出意外,数据保存成功。
不要试着把很多图片直接保存到数据库中,图片的存储与查询会比较慢,会严重拖累数据库性能。另外数据库的体积也会变得臃肿不堪,现在可是一个以瘦为美的世界!
如何读取数据库中保存的图片?
相信你一定能找到答案。
3. 总结
本节课程以体验式的方式感受了 Session 为开发者提供的常用方法。
对于类似的操作,Hibernate 会有备选方法选择,其内在的具体细节将在后续课程一一揭晓。
不要质疑 Hibernate 为什么要提供看似雷同的方法,真实场景中的需求要比 Hibernate 所能想到的更复杂。Hibenate 只是想以周全的态度为开发者保驾护航。
Hibernate 对开发者爱得深,细言碎语也就多!!