我如何在内存中的进程的事务? [英] How do I make an in-memory process transactional?

查看:101
本文介绍了我如何在内存中的进程的事务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很熟悉使用事务RDBMS,但我将如何确保修改我的内存中的数据提出,如果交易失败被回滚? ?如果我还没有使用一个数据库是什么



下面是一个人为的例子:

 公共无效TransactionalMethod()
{
VAR项目= GetListOfItems();

的foreach(在项目VAR项目)
{
MethodThatMayThrowException(项目);

item.Processed = TRUE;
}
}

在我的例子,我可能要进行的更改在列表中的项目以某种方式被回滚,但我怎么能做到这一点?



我知道软件事务内存,但不很了解它似乎相当实验性的。我知道补偿的交易的概念也是如此,但招致写作的开销做/撤销代码。



颠覆看来对付更新错误。通过运行清理命令工作副本



任何想法



更新?

里德·科普塞提供的an出色答卷,其中包括:


$ b $在数据复制b]

工作,更新提交原件。




这需要我的问题再一个级别 - 如果出现什么错误的在提交?所以,我们常常认为的承诺作为直接操作,但实际上它可能会作出了很多的数据很多变化。如果有喜欢的 OutOfMemoryException异常取值不可避免的事情而被应用提交,会发生什么?



在不利的一面,如果人去了回滚选项,如果有异常的回滚过程会发生什么?我了解的东西,如Oracle RDBMS都有回滚段的概念,并撤销日志与事,但假设没有序列化到磁盘(其中如果不是序列化到磁盘它没有发生,崩溃意味着你可以调查这些日志并从中恢复),这是真的有可能。



更新2:

的的answer 从的亚历取得了良好的建议:即一个更新不同的对象,然后,提交阶段被简单地转移到新的对象来改变参照当前对象。他更进一步建议你更改对象实际上是修改的对象的列表。



我明白他在说什么(我认为),我想使问题因此更加复杂的:



如何,鉴于这种情况下,你处理的锁?想象一下,你有一个客户列表:

  VAR的客户=新词典< CustomerKey,客户和GT;(); 

现在,你要做出改变为部分的客户,如何申请没有锁定和替换整个列表中的那些变化?例如:

  VAR customerTx =新词典< CustomerKey,客户和GT;(); 

的foreach(VAR的客户在customers.Values)
{
VAR updatedCust = customer.Clone();
customerTx.Add(GetKey(updatedCust),updatedCust);

如果(CalculateRevenueMightThrowException(客户)> = 10000)
{
updatedCust.Preferred = TRUE;
}
}



我如何提交?这(Alex的建议)将意味着同时更换名单基准锁全部客户:

 锁(客户)
{
客户= customerTx;
}



而如果通过,修改原始列表参考我循环,它不是原子,一个和跌倒的问题,如果它通过中途崩溃是什么的犯规:

 的foreach(在customerTx VAR KVP)
{
客户[kvp.Key] = kvp.Value;
}


解决方案

几乎每一个做选择这需要三种基本方法之一:




  1. 请您数据的副本修改之前,恢复到回退状态,如果中止
  2. 在数据的拷贝工作,更新提交原件。

  3. 保留更改日志到您的数据,撤消其在中止的情况下,



例如,的软件事务内存,其中你提到,遵循第三种方法。有关的好处是,它可以在处理数据乐观,刚扔掉一个成功提交日志。


I'm very familiar with using a transaction RDBMS, but how would I make sure that changes made to my in-memory data are rolled back if the transaction fails? What if I'm not even using a database?

Here's a contrived example:

public void TransactionalMethod()
{
    var items = GetListOfItems();

    foreach (var item in items)
    {		
    	MethodThatMayThrowException(item);

    	item.Processed = true;
    }
}

In my example, I might want the changes made to the items in the list to somehow be rolled back, but how can I accomplish this?

I am aware of "software transactional memory" but don't know much about it and it seems fairly experimental. I'm aware of the concept of "compensatable transactions", too, but that incurs the overhead of writing do/undo code.

Subversion seems to deal with errors updating a working copy by making you run the "cleanup" command.

Any ideas?

UPDATE:
Reed Copsey offers an excellent answer, including:

Work on a copy of data, update original on commit.

This takes my question one level further - what if an error occurs during the commit? We so often think of the commit as an immediate operation, but in reality it may be making many changes to a lot of data. What happens if there are unavoidable things like OutOfMemoryExceptions while the commit is being applied?

On the flipside, if one goes for a rollback option, what happens if there's an exception during the rollback? I understand things like Oracle RDBMS has the concept of rollback segments and UNDO logs and things, but assuming there's no serialisation to disk (where if it isn't serialised to disk it didn't happen, and a crash means you can investigate those logs and recover from it), is this really possible?

UPDATE 2:
An answer from Alex made a good suggestion: namely that one updates a different object, then, the commit phase is simply changing the reference to the current object over to the new object. He went further to suggest that the object you change is effectively a list of the modified objects.

I understand what he's saying (I think), and I want to make the question more complex as a result:

How, given this scenario, do you deal with locking? Imagine you have a list of customers:

var customers = new Dictionary<CustomerKey, Customer>();

Now, you want to make a change to some of those customers, how do you apply those changes without locking and replacing the entire list? For example:

var customerTx = new Dictionary<CustomerKey, Customer>();

foreach (var customer in customers.Values)	
{
	var updatedCust = customer.Clone();		
	customerTx.Add(GetKey(updatedCust), updatedCust);

	if (CalculateRevenueMightThrowException(customer) >= 10000)
	{
		updatedCust.Preferred = true;
	}
}

How do I commit? This (Alex's suggestion) will mean locking all customers while replacing the list reference:

lock (customers)
{
	customers = customerTx;
}

Whereas if I loop through, modifying the reference in the original list, it's not atomic,a and falls foul of the "what if it crashes partway through" problem:

foreach (var kvp in customerTx)
{
	customers[kvp.Key] = kvp.Value;
}

解决方案

Pretty much every option for doing this requires one of three basic methods:

  1. Make a copy of your data before modifications, to revert to a rollback state if aborted.
  2. Work on a copy of data, update original on commit.
  3. Keep a log of changes to your data, to undo them in the case of an abort.

For example, Software Transactional Memory, which you mentioned, follows the third approach. The nice thing about that is that it can work on the data optimistically, and just throw away the log on a successful commit.

这篇关于我如何在内存中的进程的事务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆