POJO的交易 [英] Transaction for POJOs

查看:69
本文介绍了POJO的交易的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一种方法,该方法类似于:

I'm implementing a method that does something like:

...
try {
   myPojo.setProperty("foo");
   myService.execute(myPojo);
} catch (Exception e) {
   logger.error(e.getMessage(), e);
}
...

如果我的服务从pojo属性的此try块引发了某些异常,则它将具有新值.有什么方法可以启动一种用于pojo更改的事务,并在出现问题时将其回滚?

If some exception is thrown by my service from this try block on pojo property will have the new value. Is there some way to start a kind of transaction for pojo changes and roll it back if something goes wrong?

类似的东西:

PojoTransaction pt = startPojoTransaction();
transactionedPojo = pt.handleByTransaction(myPojo);
try {
   transactionedPojo.setProperty("foo");
   myService.execute(transactionedPojo);
   pt.commit;
} catch (Exception e) {
   logger.error(e.getMessage(), e);
}

或类似的东西...

推荐答案

我想到这个主意,这远非完美,只是一个简单的概念证明.此实现存在陷阱:

I toyed around with the idea, this is far from perfect, just a simple proof of concept. There are pitfalls in this implementation:

  • 它仅尝试调用给定源的无参数构造函数 对象来创建目标副本,需要一些逻辑来选择正确的构造函数(或仅支持Cloneables?)
  • 仅复制在类中声明的字段,而不是从超类复制(可以通过遍历继承树并复制任何超类字段来解决此问题)
  • 如果字段是复杂类型,则仅将引用复制到目标对象,因此对它们的任何更改将不会进行事务处理,因为源和目标都共享同一实例(可通过递归创建嵌套对象和副本的副本来解决)复制它们的值,需要遍历整个对象图,从源头开始,然后在提交时执行相反的操作
  • It only tries to call a parameterless constructor of the given source object to create the target-copy, would need some logic to select a correct constructor (or only support Cloneables?)
  • Only copies fields declared in the class, not from superclasses (this problem can be solved walking through the inheritance tree and copying any superclass fields)
  • If the fields are complex types, only the references are copied to target-object, so any changes to them will not be transactional, as both the source and target share the same instance (solvable by recursively creating copies of nested objects and copying their values, requires walking through the entire object-graph, starting from source, and then doing it vice-versa on commit-time)

但是,从现在开始改进,我相信它可能会变得非常有用.这是POC:

But, improving from here, I believe it could become very usable. Here's the POC:

import java.lang.reflect.Field;

import org.junit.Assert;
import org.junit.Test;

public class PojoTransactionTest
{
    public static class PojoTransaction<T>
    {
        /**
         * This is the original (unmodified) object
         */
        private T source;

        /**
         * This is the object modified by within the transaction
         */
        private T target;

        /**
         * Creates a new transaction for the given source object
         * @param source    Source object to modify transactionally
         */
        public PojoTransaction(T source)
        {
            try
            {
                this.source = source;
                this.target = (T)source.getClass().newInstance(); //Note: this only supports parameterless constructors

                copyState(source, target);
            }
            catch(Exception e)
            {
                throw new RuntimeException("Failed to create PojoTransaction", e);
            }
        }

        /**
         * Copies state (member fields) from object to another
         * @param from      Object to copy from
         * @param to        Object to copy to
         * @throws IllegalAccessException
         */
        private void copyState(T from, T to) throws IllegalAccessException
        {
            //Copy internal state to target, note that this will NOT copy fields from superclasses
            for(Field f : from.getClass().getDeclaredFields())
            {
                f.setAccessible(true);
                f.set(to, f.get(from));
            }
        }

        /**
         * Returns the transaction target object, this is the one you should modify during transaction
         * @return Target object
         */
        public T getTransactionTarget()
        {
            return target;
        }

        /**
         * Copies the changes from target object back to original object
         */
        public void commit()
        {
            try
            {
                copyState(target, source);
            }
            catch(Exception e)
            {
                throw new RuntimeException("Failed to change state of original object", e);
            }
        }
    }

    public static class TestData
    {
        private String strValue = "TEST";
        private int intValue = 1;
        private float floatValue = 3.1415f;

        public String getStrValue()
        {
            return strValue;
        }

        public void setStrValue(String strValue)
        {
            this.strValue = strValue;
        }

        public int getIntValue()
        {
            return intValue;
        }

        public void setIntValue(int intValue)
        {
            this.intValue = intValue;
        }

        public float getFloatValue()
        {
            return floatValue;
        }

        public void setFloatValue(float floatValue)
        {
            this.floatValue = floatValue;
        }

    }

    @Test
    public void testTransaction()
    {
        //Create some test data
        TestData orig = new TestData();

        //Create transaction for the test data, get the "transaction target"-object from transaction
        PojoTransaction<TestData> tx = new PojoTransaction<TestData>(orig);
        TestData target = tx.getTransactionTarget();
        target.setFloatValue(1.0f);
        target.setIntValue(5);
        target.setStrValue("Another string");

        //Original object is still at the original values
        Assert.assertEquals(1, orig.getIntValue());
        Assert.assertEquals(3.1415f, orig.getFloatValue(), 0.001f);
        Assert.assertEquals("TEST", orig.getStrValue());

        //Commit transaction
        tx.commit();

        //The "orig"-object should now have the changes made to "transaction target"-object
        Assert.assertEquals(5, orig.getIntValue());
        Assert.assertEquals(1.0f, orig.getFloatValue(), 0.001f);
        Assert.assertEquals("Another string", orig.getStrValue());
    }

}

这篇关于POJO的交易的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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