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 对开发者爱得深,细言碎语也就多!!
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
