an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe

hibernate的flush机制 对hibernate的flush机制有兴趣可以看看 立即下载

        这是在一次事务提交时遇到的异常。
        an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
net.sf.hibernate.AssertionFailure: possible nonthreadsafe access to session
注:非possible non-threadsafe access to the session (那是另外的错误,类似但不一样)

  

        这个异常应该很多的朋友都遇到过,原因可能各不相同。但所有的异常都应该是在flush或者事务提交的过程中发生的。这一般由我们在事务开始至事务提交的过程中进行了不正确的操作导致,也会在多线程同时操作一个Session时发生,这里我们仅仅讨论单线程的情况,多线程除了线程同步外基本与此相同。


        至于具体是什么样的错误操作那?我给大家看一个例子(假设Hibernate配置正确,为保持代码简洁,不引入包及处理任何异常)


SessionFactory sf = new Configuration().configure().buildSessionFactory() ;
Session s = sf.openSession();
Cat cat = new Cat();
Transaction tran = s.beginTransaction(); (1)
s.save(cat); (2)(此处同样可以为update delete)
s.evict(cat); (3)
tran.commit(); (4)
s.close();(5)

        这就是引起此异常的典型错误。我当时就遇到了这个异常,检查代码时根本没感觉到这段代码出了问题,想当然的认为在Session上开始一个事务,通过Session将对象存入数据库,再将这个对象从Session上拆离,提交事务,这是一个很正常的流程。如果这里正常的话,那问题一定在别处。

    

        问题恰恰就在这里,我的想法也许没有错,但是一个错误的论据所引出的观点永远都不可能是正确的。因为我一直以为直接在对数据库进行操作,忘记了在我与数据库之间隔了一个Hibernate,Hibernate在为我们提供持久化服务的同时,也改变了我们对数据库的操作方式,这种方式与我们直接的数据库操作有着很多的不同,正因为我们对这种方式没有一个大致的了解造成了我们的应用并未得到预先设想的结果。


        那Hibernate的持久化机制到底有什么不同那?简单的说,Hibernate在数据库层之上实现了一个缓存区,当应用save或者update一个对象时,Hibernate并未将这个对象实际的写入数据库中,而仅仅是在缓存中根据应用的行为做了登记,在真正需要将缓存中的数据flush入数据库时才执行先前登记的所有行为。


        在实际执行的过程中,每个Session是通过几个映射和集合来维护所有与该Session建立了关联的对象以及应用对这些对象所进行的操作的,与我们这次讨论有关的有entityEntries(与Session相关联的对象的映射)、insertions(所有的插入操作集合)、deletions(删除操作集合)、updates(更新操作集合)。下面我就开始解释在最开始的例子中,Hibernate到底是怎样运作的。
        (1)生成一个事务的对象,并标记当前的Session处于事务状态(注:此时并未启动数据库级事务)。
        (2)应用使用s.save保存cat对象,这个时候Session将cat这个对象放入entityEntries,用来标记cat已经和当前的会话建立了关联,由于应用对cat做了保存的操作,Session还要在insertions中登记应用的这个插入行为(行为包括:对象引用、对象id、Session、持久化处理类)。
        (3)s.evict(cat)将cat对象从s会话中拆离,这时s会从entityEntries中将cat这个对象移出。
        (4)事务提交,需要将所有缓存flush入数据库,Session启动一个事务,并按照insert,update,……,delete的顺序提交所有之前登记的操作(注意:所有insert执行完毕后才会执行update,这里的特殊处理也可能会将你的程序搞得一团糟,如需要控制操作的执行顺序,要善于使用flush),现在cat不在entityEntries中,但在执行insert的行为时只需要访问insertions就足够了,所以此时不会有任何的异常。异常出现在插入后通知Session该对象已经插入完毕这个步骤上,这个步骤中需要将entityEntries中cat的existsInDatabase标志置为true,由于cat并不存在于entityEntries中,此时Hibernate就认为insertions和entityEntries可能因为线程安全的问题产生了不同步(也不知道Hibernate的开发者是否考虑到例子中的处理方式,如果没有的话,这也许算是一个bug吧),于是一个net.sf.hibernate.AssertionFailure就被抛出,程序终止。


        我想现在大家应该明白例子中的程序到底哪里有问题了吧,我们的错误的认为s.save会立即的执行,而将cat对象过早的与Session拆离,造成了Session的insertions和entityEntries中内容的不同步。所以我们在做此类操作时一定要清楚Hibernate什么时候会将数据flush入数据库,在未flush之前不要将已进行操作的对象从Session上拆离。


        对于这个错误的解决方法是,我们可以在(2)和(3)之间插入一个s.flush(),强制Session将缓存中的数据flush入数据库(此时Hibernate会提前启动事务,将(2)中的save登记的insert语句登记在数据库事务中,并将所有操作集合清空),这样在(4)事务提交时insertions集合就已经是空的了,即使我们拆离了cat也不会有任何的异常了。

        前面简单的介绍了一下Hibernate的flush机制和对我们程序可能带来的影响以及相应的解决方法,Hibernate的缓存机制还会在其他的方面给我们的程序带来一些意想不到的影响。看下面的例子:


(name为cat表的主键)
Cat cat = new Cat();
cat.setName(“tom”);
s.save(cat);
cat.setName(“mary”);
s.update(cat);(6)
Cat littleCat = new Cat();
littleCat.setName(“tom”);
s.save(littleCat);
s.flush();

        这个例子看起来有什么问题?估计不了解Hibernate缓存机制的人多半会说没有问题,但它也一样不能按照我们的思路正常运行,在flush过程中会产生主键冲突,可能你想问:“在save(littleCat)之前不是已经更改cat.name并已经更新了么?为什么还会发生主键冲突那?”这里的原因就是我在解释第一个例子时所提到的缓存flush顺序的问题,Hibernate按照insert,update,……,delete的顺序提交所有登记的操作,所以你的s.update(cat)虽然在程序中出现在s.save(littleCat)之前,但是在flush的过程中,所有的save都将在update之前执行,这就造成了主键冲突的发生。


        这个例子中的更改方法一样是在(6)之后加入s.flush()强制Session在保存littleCat之前更新cat的name。这样在第二次flush时就只会执行s.save(littleCat)这次登记的动作,这样就不会出现主键冲突的状况。


        再看一个例子(很奇怪的例子,但是能够说明问题)

Cat cat = new Cat();
cat.setName(“tom”);
s.save(cat); (7)
s.delete(cat);(8)
cat.id=null;(9)
s.save(cat);(10)
s.flush();

        这个例子在运行时会产生异常net.sf.hibernate.HibernateException: identifier of an instance of Cat altered from 8b818e920a86f038010a86f03a9d0001 to null

        这里例子也是有关于缓存的问题,但是原因稍有不同:
      (7)和(2)的处理相同。
      (8)Session会在deletions中登记这个删除动作,同时更新entityEntries中该对象的登记状态为DELETED。
      (9)Cat类的标识符字段为id,将其置为null便于重新分配id并保存进数据库。
     (10)此时Session会首先在entityEntries查找cat对象是否曾经与Session做过关联,因为cat只改变了属性值,引用并未改变,所以会取得状态为     DELETED的那个登记对象。由于第二次保存的对象已经在当前Session中删除,save会强制Session将缓存flush才会继续,flush的过程中首先要执行最开始的save动作,在这个save中检查了cat这个对象的id是否与原来执行动作时的id相同。不幸的是,此时cat的id被赋为null,异常被抛出,程序终止(此处要注意,我们在以后的开发过程尽量不要在flush之前改变已经进行了操作的对象的id)。

这个例子中的错误也是由于缓存的延时更新造成的(当然,与不正规的使用Hibernate也有关系),处理方法有两种:
1、在(8)之后flush,这样就可以保证(10)处save将cat作为一个全新的对象进行保存。
2、删除(9),这样第二次save所引起的强制flush可以正常的执行,在数据库中插入cat对象后将其删除,然后继续第二次save重新插入cat对象,此时cat的id仍与从前一致。


        这两种方法可以根据不同的需要来使用,呵呵,总觉得好像是很不正规的方式来解决问题,但是问题本身也不够正规,只希望能够在应用开发中给大家一些帮助,不对的地方也希望各位给与指正。


   总的来说,由于Hibernate的flush处理机制,我们在一些复杂的对象更新和保存的过程中就要考虑数据库操作顺序的改变以及延时flush是否对程序的结果有影响。如果确实存在着影响,那就可以在需要保持这种操作顺序的位置加入flush强制Hibernate将缓存中记录的操作flush入数据库,这样看起来也许不太美观,但很有效。

http://blog.youkuaiyun.com/tianlincao/article/details/6040228

Hibernate的事务处理机制和flush方法的用法.docx 关于在使用 hibernate 在提交事务时常遇到的异常: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) net.sf.hibernate.AssertionFailure: possible nonthreadsafe access to session 其实这个异常一般都是和我们在操作session flush方法和提交事务过程中会抛出的,下面就具体结合session的事务和声明周期来具体分析下,为什么会有这样的异常; 立即下载

相关推荐

详细Ubuntu 22.04 配置最新UR机械臂仿真环境(ros2-humble, ur-sim, ur-ros2-driver)

使用ubuntu22.04.01和ur-sim, ur-driver进行ur机械臂的仿真

verloge的博客 1万+

hibernate-save-AssertionFailure HHH000099: an assertion failure this may indicate a bug in Hibernate

ERROR AssertionFailure HHH000099: an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in ...

博客 3426

【ros】ROS1的安装和相关使用方法

主要学习ros相关内容

Greary的博客 2380

hibernate一对多向数据库保存数据失败问题解决

先贴出报错内容 一月 05, 2019 10:01:14 下午 org.hibernate.util.JDBCExceptionReporter logExceptions 警告: SQL Error: 1364, SQLState: HY000 一月 05, 2019 10:01:14 下午 org.hibernate.util.JDBCExceptionReporter logExcepti...

sjz_1014的博客 1160

工业视觉检测实战指南:从硬件配置到AI算法部署

本文提供了一套完整的工业视觉检测系统搭建实战指南。从硬件选型(相机、光源、镜头、工控机)到AI算法(深度学习模型)部署,详细解析了如何为生产线配置一双“会思考的眼睛”。重点探讨了深度学习算法在复杂缺陷识别中的应用,并分享了模型训练、优化及云边协同部署的实战心得,旨在帮助工程师实现从实验室Demo到7x24小时稳定运行的工业落地。

weixin_29051193的博客 459

鸿蒙OS开机动画背后的秘密:从代码到视觉的完整解析(附源码分析)

本文深入解析了鸿蒙OS开机动画的系统级实现原理。从bootanimation服务的启动配置、与Render Service的协同,到基于VSync信号的帧率同步与绘制流水线,结合OpenHarmony源码进行了逐行解读。文章揭示了其事件驱动的优雅退出机制,并探讨了视频支持、多屏适配等高级特性与定制化可能,为开发者理解鸿蒙图形子系统提供了硬核技术视角。

sony5的博客 974

Hibernate利用save()方法时报mysql语法错误

在利用hibernate的session.save()方法生成table,并插入数据时,报了如下错误 ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'O

soeasy2017的博客 1296

HP MSA 2050磁盘阵列配置步骤

一、盘阵与服务器直接连接 1.1 单控制器配置:一台服务器/ 一个 HBA/ 单路径 1.2 双控制器配置:两台服务器/ 每台服务器一个 HBA/ 双路径 二、通过交换机(一般光纤交换机) 2.1 双控制器配置:两台服务器/ 两台交换机 三、配置MSA2050 3.1在完成硬件安装后,可以访问控制器模块的基于 Web 的管理界面 SMU (存储 管理实用程序),以便监视和管理此存储系统。 首先...

jw5493的博客 1万+

Hibernate的session.flush做了什么呢?

这是在一次事务提交时遇到的异常。    an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)net.sf.hibernate.AssertionFailure: possible nonthreadsaf

Now . Or Never `` 796

基于java的汉服商城管理系统设计与实现的详细项目实例

本文介绍了一个基于Java的汉服商城管理系统设计与实现项目。该项目采用三层架构设计,包含用户模块、商品管理、订单处理、支付结算等核心功能,支持多角色权限控制和响应式前端界面。 系统创新点包括: 专业化的汉服商品管理,支持多规格属性组合 高并发订单处理机制,确保库存实时同步 个性化智能推荐算法提升用户体验 细粒度权限控制保障系统安全 项目采用SpringBoot+MyBatis技术栈,前端使用React框架实现跨设备兼容。数据库设计包含用户表、商品表、订单表等10个核心表,通过事务管理确保数据一致性。 系统解

优质创作者: 人工智能技术领域 对于有一定基础的 MATLAB和Python带具体需求都可以详谈 MATLAB和Python可以提供代码调试服务加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢 804

【x264编码器】章节1——x264编码流程及基于x264的编码器demo

提供了一种方便的方式来根据指定的配置profile应用相应的设置到 x264 参数结构体上。不同的配置文件类型会对参数结构体进行不同的修改,以满足特定的编码需求。然后是编码器参数,包括帧参考数、最大关键帧间隔、最小关键帧间隔、B 帧数、场景切换阈值等。结构体的成员进行赋值,将其初始化为默认值。之后是一些编码器设置,如去块滤波、CABAC 编码、码率控制方法、参考帧压缩系数等。接下来是一系列与视频属性相关的参数,如色度格式、宽度、高度、宽高比等。然后是一些与日志输出、分析类型、量化矩阵等相关的参数。

vcvdv123的博客 5746

hibernate 批量保存数据时存在唯一键unique值重复时报错的解决方式

错误代码: org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions WARN: SQL Error: 1062, SQLSan assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use

if_you_can_please_do的博客 7702

【Clickhouse】Cannot allocate block number in Zookeeper write prefix view location

我有一个问题,我CK集群跑批的时候,replicated表变成只读的了下面是CK的报错和当时ZK的日志。下面是zk报错开始 我认为是写入的时候,压力太大,ZK扛不住了,就按照博客里的建议优化了ZK的参数,现在偶尔还会只读,zk报错都是图里的那种clickhouse的集群是5分片的集群,数据量比较大。每小时批量一次,每次2-10W条数据,字段的话,不到200个字段,使用的 jdbc sink写入。

九师兄 836

hibernate的事务处理机制以及flush方法的作用

关于在使用hibernate在提交事务时常遇到的异常:        an assertion failure occured (this may indicate a bug in Hibernate, butis more likely due to unsafe use of the session) net.sf.hibernate.AssertionFailure: possible

u012534354的博客 3113

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

possible non-threadsafe access to the session 和 java.util.ConcurrentModificationException: null

项目场景: springboot+spring data jpa 问题描述: 项目有一个接口查询有点慢但是查询处数据之后还要对数据进行处理,刚开始使用了 集合的 stream属性,由于查询的有点慢,于是我改成了并行流 parallelStream ,查询接口速度是有所提升,但是后来发现,使用一段时间之后会不定时的报 possible non-threadsafe access to the session 和 [2021-09-03 14:42:36] [ERROR] [org.springframewor

lierjun 的专栏 1813

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Hibernate 中session.evict(obj):possible nonthreadsafe access to session

Hibernate 中session.evict(obj):possible nonthreadsafe access to session 使用Hibernate 中session.evict方法时,报了如题的错误,另外,还有如下的提示:Hibernate: insert into TEST (version, NAME, CODE, ID) values (?, ?, ?, ?)23:

one_dollar 7522

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

浅谈Hibernate的flush机制

http://www.javaresearch.org/article/51711.htm随着Hibernate在Java开发中的广泛应用,我们在使用Hibernate进行对象持久化操作中也遇到了各种各样的问题。这些问题往往都是我们对Hibernate缺乏了解所致,这里我讲个我从前遇到的问题及一些想法,希望能给大家一点借鉴。        这是在一次事务提交时遇到的异常。       an a

900
上一篇: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracl
下一篇: 正在连接到192.168.1.118 不能打开到主机的连接, 在端口 1521: 连接失败
cpp_lzth
博客等级 码龄19年 125粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值