2019独角兽企业重金招聘Python工程师标准>>>

1.Hibernate批量处理

在Hibernate应用中,有两种批量处理方法:一种是通过Hibernate的缓存,另一种是绕过Hibernate,直接调用JDBC API来处理。

1)批量插入

(1)通过Hibernate的缓存进行批量插入

使用这种方法时,首先要在Hibernate的配置文件hibernate.cfg.xml中设置批量尺寸属性hibernate.jdbc.batch_size,且最好关闭Hibernate的二级缓存以提高效率。

例如:

<hibernate-configuration><session-factory>…<property name="hibernate.jdbc.batch_size">50</property>                         // 设置批量尺寸<property name="hibernate.cache.use_second_level_cache">false</property>         // 关闭二级缓存</session-factory>
</hibernate-configuration>

下面以4.2.1节的例子中的课程进行批量插入为例,说明批量插入操作的具体过程,这里假设批量插入500个课程到数据中:

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
for(int i=0;i<500;i++){Kcb kcb=new Kcb();// 这里设置课程号为i,在实际应用中应该是被插入的课程对象// 已经放在集合或数组中,这里只要取出kcb.setKch(i+"");  session.save(kcb);if(i%50==0){          // 以50个课程为一个批次向数据库提交,此值应与配置的批量尺寸一致session.flush();  // 将该批量数据立即插入数据库中session.clear();  // 清空缓存区,释放内存供下批数据使用}
}
ts.commit();
HibernateSessionFactory.closeSession();

(2)绕过Hibernate直接调用JDBC进行插入

由于Hibernate只是对JDBC进行了轻量级的封装,因此完全可以绕过Hibernate直接调用JDBC进行批量插入。因此上例可以改成如下代码:

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
Connection conn=session.connection();
try {PreparedStatement  stmt=conn.prepareStatement("insert into KCB(KCH) values(?)");for (int i=0; i < 500; i++) {stmt.setString(1, i+"");stmt.addBatch();                  // 添加到批处理命令中}stmt.executeBatch();                   // 执行批处理任务
} catch (SQLException e) {e.printStackTrace();
}
ts.commit();
HibernateSessionFactory.closeSession();

2)批量更新

(1)由Hibernate直接进行批量更新

为了使Hibernate的HQL直接支持update/delete的批量更新语法,首先要在Hibernate的配置文件hibernate.cfg.xml中设置HQL/SQL查询翻译器属性hibernate.query.factory_class。

<hibernate-configuration>       <session-factory>……<propertyname="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</property></session-factory>
<hibernate-configuration>

下面使用HQL批量更新把课程表中的XS修改为30。由于这里是用Hibernate操作,故HQL要用类对象及其属性。

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
//在HQL查询中使用update进行批量更新
Query query=session.createQuery("update Kcb set xs=30");
query.executeUpdate();
ts.commit();
HibernateSessionFactory.closeSession();

(2)绕过Hibernate调用JDBC进行批量更新

由于这里是直接操作数据库,故要操作对应表,而不是类。

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
Connection conn=session.connection();
try {Statement stmt=conn.createStatement();//调用JDBC的update进行批量更新stmt.executeUpdate("update KCB set XS=30");
} catch (SQLException e) {e.printStackTrace();
}
ts.commit();
HibernateSessionFactory.closeSession();

3)批量删除

(1)由Hibernate直接进行批量删除

与批量更新一样,为了使Hibernate的HQL直接支持update/delete的批量删除语法,首先要在Hibernate的配置文件hibernate.cfg.xml中设置HQL/SQL查询翻译器属性hibernate.query.factory_class。

<hibernate-configuration>       <session-factory>……<propertyname="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</property></session-factory>
<hibernate-configuration>

下面将使用HQL批量删除课程表中课程号大于200的课程。

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
//在HQL查询中使用delete进行批量删除
Query query=session.createQuery("delete Kcb where kch>200");
query.executeUpdate();
ts.commit();
HibernateSessionFactory.closeSession();

(2)绕过Hibernate调用JDBC进行批量删除

同样删除课程表中课程号大于200的课程。

Session session=HibernateSessionFactory.getSession();
Transaction ts=session.beginTransaction();
Connection conn=session.connection();
try {Statement stmt= conn.createStatement();//调用JDBC的delete进行批量删除stmt.executeUpdate("delete from KCB where KCH>200");
} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();
}
ts.commit();
HibernateSessionFactory.closeSession();

2.实体对象生命周期

是Hibernate应用的一个关键概念。这里的实体对象,特指Hibernate O/R映射关系中的域对象(即O/R中的O)

实体对象的生命周期有以下3种状态。

1)transient(瞬时态)

瞬时态,即实体对象在内存中的存在与数据库中的记录无关。如下面的代码:

Student stu=new Student();
stu.setSnumber("081101");
stu.setSname("李方方");
stu.setSage(21);

2)persisent(持久态)

在这种状态下,实体对象的引用被纳入Hibernate实体容器中加以管理。处于持久状态的对象,其变更将由Hibernate固化到数据库中。例如下面的代码。

Student stu=new Student();
Student stu1=new Student();
stu.setSnumber("081101");
stu.setSname("李方方");
stu.setSage(21);
stu1.setSnumber("081102");
stu1.setSname("程明");
stu1.setSage(22);                                        // 到此为止,stu和stu1均处于瞬时态
Transaction tx=session.beginTransaction();
session.save(stu); // 通过save()方法,stu对象转换为持久态,由Hibernate纳入实体管理容器,而stu1仍然处于瞬时态
// 事务提交之后,数据库表中插入一条学生的记录,对于stu1则无任何操作
tx.commit();
Transaction tx2=session.beginTransaction();
stu.setSname("李方");
stu1.setSname("程明明");
// 虽然这个事务中没有显示调用session.save()方法保存stu对象,但是由于stu为持久态,将自动被固化到数据库,因此数据库的学号为“081101” 学生记录的姓名已被更改为“李方”,此时stu1仍然是一个普通Java对象,对数据库未产生任何影响
tx2.commit();

处于瞬时态的对象,可以通过Session的save()方法转换成持久状态。同样,如果一个实体对象由Hibernate加载,那么,它也处于持久状态。例如下面的

// 由Hibernate返回的持久对象
Student stu=(Student)session.load(Student.class,new Integer(1));

3)Detached(脱管状态)

处于持久态的对象,其对应的Session实例关闭之后,此对象就处于脱管状态。Session实例可以看做是持久对象的宿主,一旦此宿主失效,其从属的持久对象进入脱管状态。如下面的代码:

Student stu=new Student();// stu处于瞬时态
Student stu1=new Student();
stu.setSnumber("081101");
stu.setSname("李方方");
stu.setSage(21);
stu1.setSnumber("081102");
stu1.setSname("程明");
stu1.setSage(22);
Transaction tx=session.beginTransaction();
session.save(stu);// stu对象由Hibernate纳入管理容器,处于持久状态
tx.commit();
session.close();// stu对象状态为脱管态,因为与其关联的session已经关闭

 瞬时状态的对象与库表中的数据库缺乏对应关系;而托管状态的对象,却在库表中存在相应的记录,只不过由于其脱离Session这个数据库操作平台,其状态改变无法更新到数据库表中

3.Hibernate事务管理

事务是数据库并发控制不可分隔的基本工作单位,具有原子性、一致性、隔离性和持久性的特点。

事务(Transcation)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免只修改了一部分导致数据不完整,或者在修改时受到用户干扰。

1)基于JDBC的事务管理

Hibernate是JDBC的轻量级封装,本身并不具备事务管理能力。在事务管理层,Hibernate将其委托给底层的JDBC或JTA,以实现事务管理和调度功能

在JDBC的数据库操作中,一项事务是由一条或多条表达式组成的不可分割的工作单元,通过提交commit()或回滚rollback()来结束事务的操作。

在JDBC中,事物默认是自动提交。也就是说,一条更新表达式代表一项事物操作。操作成功后,系统将自动调用commit()提交。否则将调用rollback()回滚。

在JDBC中,可以通过调用setAutoCommit(false)禁止自动提交,之后就可以把多个数据库操作的表达式作为一个事物,在操作完成后调用commit()进行整体提交。

将事务管理委托给JDBC进行处理是最简单的实现方式,Hibernate对于JDBC事务的封装也比较简单。如下面的代码:

Session session=sessionFactory.openSession();
Transaction tx=session.beginTransaction();
session.save(room);
tx.commit();

从JDBC层面而言,上面的代码实际上对应着:

Connection cn=getConnection;
cn.setAutoCommit(false);
// JDBC调用相关的SQL语句
cn.commit();

在sessionFactory.open()语句中,Hibernate会初始化数据库连接。与此同时,将其AutoCommit()设为关闭状态(false)。因此在调用commit()之前,下面的代码不会对数据库产生任何效果:

session session=session.Factory.openSession();
session.save(room);
session.close();

如果要使代码真正作用到数据库,必须显示地调用Transaction指令:

Session session =sessionFactory.openSession();
Transaction tx=sessio.beginTransaction();
session.save(room);
tx.commit();
session.close();

2)基于JTA的事务管理概念

JTA(Java Transaction API)是由Java EE Transaction Manager去管理的事务。其最大的特点是调用UserTransaction接口的begin、commit和rollback方法来完成事务范围的界定、事务的提交和回滚。JTA可以实现统一事务对应不同的数据库。

JTA主要用于分布式的多个数据源的两阶段提交的事务,而JDBC的Connection提供单个数据源的事务。后者因为只涉及一个数据源,所以其事务可以由数据库自己单独实现。而JTA事务因为其分布式和多数据源的特性,不可能由任何一个数据源实现事务。因此,JTA中的事务是由“事务管理器”实现的。它会在多个数据源之间统筹事务,具体使用的技术就是所谓的“两阶段提交”

3)锁

业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算处理中,希望对某个结算时间点的数据进行处理,而不希望在结算过程中(可能是几秒,也可能是几个小时),数据再发生变化。此时,需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制就是所谓的“锁”,即给选定的目标数据上锁,使其无法被其他程序修改。

Hibernate支持两种锁机制,悲观锁(Pessimistic Locking)和乐观锁(Optimistic Locking)。

(1)悲观锁,它指的是对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。

(2)乐观锁,悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。

乐观锁,大多是基于数据版本( Version )记录机制实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则就报错。

对于上面修改用户帐户信息的例子而言,假设数据库中帐户信息表中有一个version 字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100 。

操作员 A 此时将其读出( version=1 ),并从其帐户余额中扣除 $50( $100-$50 )。

在操作员 A 操作的过程中,操作员 B 也读入此用户信息( version=1 ),并从其帐户余额中扣除$20 ( $100-$20 )。

操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。

操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作员 A 的操作结果的可能。

需要注意的是,乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户余额更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。

附:目录《JavaEE基础实用教程》笔记说明

转载于:https://my.oschina.net/jerrypan/blog/626895

4.4 Hibernate高级功能相关推荐

  1. hibernate 高级映射 --张国亮总结第一季

    在做持久化类的时候的规定: 1).有一个默认的构造方法: 2).所有的属性都有setter和getter方法 3).有一个对象标识符Oid; 4).如果有集合属性,则必须定义成接口类型:List.Se ...

  2. RocketMQ 高级功能介绍

    1. 高级功能 1.1 消息存储 分布式队列因为有高可靠性的要求,所以数据要进行持久化存储. 消息生成者发送消息 MQ收到消息,将消息进行持久化,在存储中新增一条记录 返回ACK给生产者 MQ pus ...

  3. python数据库模块_十二、Python高级功能之Mysql数据库模块

    Python高级功能之Mysql数据库模块 安装python mysql组件 # yum -y install MySQL-python.x86_64 以下根据实例来说明: >>> ...

  4. sql取最大值的那一行_从零学会SQL:SQL高级功能

    一.什么是窗口函数 1.什么是窗口函数? 窗口函数,也叫OLAP函数(Online Analytical Processing,联机分析处理),可以对数据库数据进行实时分析处理. 窗口函数的基本语法如 ...

  5. 使用驱动器f:中的光盘之前需要将其格式化_mac虚拟光驱Daemon Tools高级功能详解—光盘刻录...

    DAEMON Tools是一种紧凑而智能的解决方案,用于在Mac上安装不同类型的虚拟光盘,并允许您创建ISO,MDX和MDS / MDF图像.通过该程序,系统可识别虚拟图像,并允许您像使用普通光盘一样 ...

  6. 实现一个可管理、增发、兑换、冻结等高级功能的代币

    本文首发于深入浅出区块链社区 原文链接:实现一个可管理.增发.兑换.冻结等高级功能的代币 本文主要介绍代币高级功能的实现: 代币管理.代币增发.代币兑换.资产冻结.Gas自动补充. 写在前面 在上一篇 ...

  7. hibernate 高级查询 query 或查询 or ,Restrictions

    hibernate 高级查询 query 或查询 or ,Restrictions 今天用了写hibernate高级查询时用了Restrictions(当然Expression也是可以以的)这个类.感 ...

  8. 利用Windows API获得系统高级功能

    利用Windows API获得系统高级功能 邹刚 VB无疑是最先进的编程工具之一,但在涉及windows 32位系统的核心编程方面--譬如一些高级功能的实现上,它仍然显得有些力不从心,这需要我们充分利 ...

  9. sql server累计求和函数_SQL基础--SQL高级功能

    一.窗口函数有什么用? 在日常工作中,经常会遇到需要在每组内排名,比如下面的业务需求: 排名问题:每个部门按业绩来排名 topN问题:找出每个部门排名前N的员工进行奖励 面对这类需求,就需要使用sql ...

  10. 项目开发--高级功能汇总

    祭奠曾经逝去的青春-- 1.高级功能汇总-->Memcached之ASP.NET实现 2.高级功能汇总-->HubbleDotNet软件安装 转载于:https://www.cnblogs ...

最新文章

  1. Python3 使用replace 替换空格无效
  2. 【Ctsc2011】幸福路径
  3. arduino灯光装置_用Arduino实现智能控制-夜间感应灯的制作
  4. linux upx 报错 NotCompressibleException
  5. 如何快速提高网站流量
  6. XML引入多scheme文件约束简单示例
  7. maven 打包时动态替换properties资源文件中的配置值
  8. cpu核心 线程 进程_科个普:进程、线程、并发、并行
  9. 韩顺平 零基础30天学会Java 学习笔记
  10. 杭州电子科技大学ACM-1096
  11. 假设检验:如何理解单侧、双侧检验的拒绝域
  12. Cesium开发基础篇 | 04空间数据可视化之Entity
  13. macOS Mojave 使用SMB局域网共享作为TimeMachine时间机器的备份盘报错Disk does not support Time Machine backups. (error 45)
  14. vs code 黑白
  15. 靴子落地,火山引擎官宣进军云市场
  16. RepRapPro赫胥黎的调试之一
  17. [附源码]计算机毕业设计儿童早教课程管理系统论文2022Springboot程序
  18. 香港大学计算机博士的就业前景,香港大学计算机博士申请2个重要条件
  19. Python编程:多线程断点下载文件
  20. 【ICLR 2023】详细解读DiffEdit:基于扩散模型的图像编辑革命性成果

热门文章

  1. 设计模式那点事读书笔记(3)----建造者模式
  2. inline-block和float
  3. SharePoint 2013 Preview Single Server 评估环境安装与简单试用
  4. 正则表达式的几种字符判断(包括数字,字母组合等)
  5. C#强化系列文章七:序列化和反序列化
  6. LOJ2257 SNOI2017 遗失的答案 容斥、高维前缀和
  7. PCL Examples
  8. Oracle 中的Interger类型
  9. LR之Java Vuser
  10. mysql学习一 常用语句