如何强制提交Spring - hibernate事务安全

时间:2014-06-26 16:43:46

标签: java database spring hibernate transactions

我们正在使用spring和hibernate作为Web应用程序: 该应用程序有一个购物车,用户可以在其中放置项目。为了保持在不同登录之间要查看的项目,购物车中的项目值存储在表格中。提交购物车时,如果需要生成订单号,项目将保存到不同的表格中。

当我们将值插入表中以获取订单号时,我们使用获取最大订单号并为其添加+1。我们使用spring transaction manager和hibernate,在代码流中我们得到订单号并更新hibernate对象以保存订单num值。当我调试时,我注意到只有在发出完整的事务时才会插入订单号实体bean。

这里的问题是当我们同时向服务器提交两个请求时,正在使用相同的订单号,并且只插入一个请求数据。无法插入另一个请求值,这又是一个唯一的请求值。 表中的订单号是唯一的。

我注意到调试时,即使在发出会话刷新后,持久层也没有插入到数据库中 session.flush()

它只更新内存并仅在spring事务结束时将数据插入db。我试图明确发出交易提交

session.getTransaction().commit();

这会立即将值插入数据库,但是在进一步的代码流显示消息时无法启动事务。

非常感谢任何帮助。

添加了: 我使用的Oracle数据库。 有一个序列号对于该表是唯一的,并且订单号也映射到它。

3 个答案:

答案 0 :(得分:1)

当多个线程执行相同的逻辑时,您的第一个问题是数字生成周围的串行访问问题。如果您可以使用Oracle序列,则会在数据库级别自动将其作为序列进行处理 保证在任何次调用它们时返回唯一值。但是,由于现在需要在服务器端进行管理,因此您需要 在整个事务边界中使用围绕数字生成逻辑的同步机制(选择max和increment by)。你可以制作服务 方法synchronized(您的服务类将是singleton和Spring管理)并声明它周围的事务边界。但是请注意,这会产生性能影响并且通常很糟糕 可扩展性。

另一个选项可能是这个的变化 - 存储要在一个单独的表中分配的id,其中一列“currentVal”并使用悲观锁 获得下一个号码。这样,主表就没有任何大锁。这样,在主实体创建事务完成时,将为序列生成器代码保持锁定。这些技术背后的主要思想是序列化 访问序列生成器并保持锁定直到主实体事务提交。也尽可能延迟数字生成器。

如果在您的设计中使用触发器很好,@ Vlad建议的解决方案很好。

关于刷新行为的问题,SQL在刷新调用时被发送到数据库,但是在声明性地提交事务或调用手动提交之前,数据不会被提交。但是,根据交易的隔离性质,交易可以看到它改变的数据而不是其他交易。

答案 1 :(得分:1)

我会设置一个触发器的订单号,该触发器将在购物车插入一个的同一交易中运行。

保存购物车后,要查看更新的订单计数,您必须致电:

session.refresh(cart);

计数不应由Hibernate(insertable/updatable = false@Transient)管理。

答案 2 :(得分:1)

请按以下步骤操作: - , 1)在不同的服务类中创建一个传播REQUIRES_NEW的服务方法。 2)在这个新方法中移动你的代码(你想要刷新到db的代码)。 3)从现有的api调用此方法(由于Spring中的代理,我们必须从不同的类调用这个新的服务方法,否则REQUIRES_NEW将无法正常工作以确保您的刷新数据。)