简体   繁体   English

如何强制提交Spring-安全地休眠事务

[英]How to force commit Spring - hibernate transaction safely

We are using spring and hibernate for an web application: The application has a shopping cart where user can place items in it. 我们在Web应用程序中使用spring和hibernate:该应用程序有一个购物车,用户可以在其中放置物品。 in order to hold the items to be viewed between different login's the item values in the shopping cart are stored in tables. 为了保留要在不同登录名之间查看的项目,购物车中的项目值存储在表中。 when submitting the shopping cart the items will be saved into different table were we need to generate the order number. 提交购物车时,如果需要生成订单号,则商品将保存到其他表格中。

When we insert the values into the table to get the order number, we use to get the max order number and add +1 to it. 当我们将值插入表中以获取订单号时,我们用于获取最大订单号并为其添加+1。 we are using spring transaction manager and hibernate, in the code flow we get the order number and update the hibernate object to hold the order num value. 我们使用的是Spring事务管理器和休眠模式,在代码流中,我们获得了订单号并更新了休眠对象以保存订单号值。 when i debug, i noticed that only when the complete transaction is issued the order number entity bean is being inserted. 调试时,我注意到只有在发出完整交易时,才会插入订单号实体bean。

Issue here is when we two request is being submitted to the server at the same time, the same order number is being used, and only one request data is getting inserted. 这里的问题是,当我们同时向服务器提交两个请求,使用相同的订单号,并且仅插入一个请求数据时。 could not insert the other request value which is again a unique one. 无法插入另一个唯一的请求值。 The order num in the table is a unique one. 表中的订单号是唯一的。

i noticed when debugging the persistant layer is not getting inserted into the database even after issuing session flush session.flush() 我注意到在调试持久层时,即使在发出会话刷新session.flush()之后也没有将其插入数据库中

its just updating the memory and inserting the data to db only at the end of the spring transaction . 它仅在spring事务结束时更新内存并将数据插入db中。 i tried explicitly issuing a commit to transaction 我试图明确发出交易承诺

session.getTransaction().commit();

this inserted the values into the database immediately, but on further code flow displayed message that could not start transaction. 这会立即将值插入数据库,但在进一步的代码流上显示了无法启动事务的消息。

Any help is highly appreciated. 非常感谢您的帮助。

Added: Oracle database i used. 补充:我使用的Oracle数据库。 There is a sequence number which is unique for that table and also the order number maps to it. 该表有一个唯一的序列号,并且订单号也映射到该表。

I would set the order number with a trigger which will run in the same transaction with the shopping cart insert one. 我将使用触发器设置订单号,该触发器将在与购物车插入一个交易的同一笔交易中运行。

After you save the shopping cart, to see the updated order count, you'll have to call: 保存购物车后,要查看更新的订单数,您必须致电:

session.refresh(cart);

The count shouldn't be managed by Hibernate ( insertable/updatable = false or @Transient ). 该计数不应该由Hibernate管理( insertable/updatable = false@Transient )。

Your first problem is that of serial access around the number generation when multiple thread are executing the same logic. 您的第一个问题是,当多个线程执行相同的逻辑时,围绕数字生成进行串行访问。 If you could use Oracle sequences this would have been automatically taken care of at the database level as the sequences are guranteed to return unique values any number of times they are called. 如果您可以使用Oracle序列,则将保证在数据库级别自动解决该问题,因为保证序列可以在调用多次后返回唯一值。 However since this needs to be now managed at server side, you would need to use synchronization mechanism around your number generation logic ( select max and increment by one) across the transaction boundary. 但是,由于现在需要在服务器端对此进行管理,因此您将需要在事务生成边界周围的数字生成逻辑(选择max并以1为增量)周围使用同步机制。 You can make the Service method synchronized ( your service class would be singleton and Spring managed) and declare the transaction boundary around it. 您可以使Service方法同步(您的服务类将是Singleton,由Spring管理),并声明其周围的事务边界。 However please note that this would be have performance implications and is usually bad for scalability. 但是请注意,这会影响性能,通常不利于可伸缩性。

Another option could be variation of this - store the id to be allocated in a seperate table with one column "currentVal" and use pessimistic lock for getting the next number. 另一个选择可能是此方法的变体-将要分配的ID存储在带有“ currentVal”列的单独表中,并使用悲观锁获取下一个数字。 This way, the main table would not have any big lock. 这样,主表将没有任何大锁。 This way a lock would be held for the sequence generator code for the time the main entity creation transaction is complete. 这样,在主要实体创建事务完成时,将为序列生成器代码保留一个锁。 The main idea behind these techniques is to serialize access to the sequence generator and hold the lock till the main entity transaction commits. 这些技术背后的主要思想是序列化对序列生成器的访问并保持锁定,直到主要实体事务提交为止。 Also delay the number generator as late as possible. 还应尽可能延迟数字生成器。

The solution suggested by @Vlad is an good one if using triggers is fine in your design. 如果在设计中使用触发器,则@Vlad建议的解决方案是一个很好的解决方案。

Regarding your question around the flush behaviour, the SQL is sent to the database at flush call, however the data is not committed until the transaction is committed declaratively or a manual commit is called. 关于冲洗行为的问题,SQL在冲洗调用时发送到数据库,但是只有在声明式提交事务或调用手动提交后,数据才提交。 The transaction can however see the data it purposes to change but not other transactions depending upon the isolation nature of transaction. 但是,根据事务的隔离性,事务可以看到要更改的数据,而其他事务则看不到。

follow these steps :- , 1) Create a service method with propagation REQUIRES_NEW in different service class . 请按照下列步骤操作:-,1)在不同的服务类中创建具有传播REQUIRES_NEW的服务方法。 2)Move your code (whatever code you want to flush in to db ) in this new method . 2)以这种新方法移动您的代码(无论您想刷新到db的所有代码)。 3)Call this method from existing api (Because of proxy in spring, we have to call this new service method from different class otherwise REQUIRES_NEW will not work which make sure your flushing data ). 3)从现有的api调用此方法(由于在春季使用了代理,我们必须从不同的类调用此新的服务方法,否则REQUIRES_NEW将无法确保您的刷新数据)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM