M
M
mitaichik2016-08-29 17:45:21
Java
mitaichik, 2016-08-29 17:45:21

Does Java/Spring have transactions for changing objects?

Hello! In java, as in spring, a beginner.
I have an object that can be used in many mets at the same time (something like an opportunist). Sometimes it needs to be changed, but not one property, but several at once. But this needs to be wrapped in something like a transaction, so that it does not happen that the client uses it when some of the fields are changed, some are not. It is necessary that either while the change is in progress, satry data is returned, or that the thread is waiting (similar to synchrnozed).
Are there any standard methods for this, or do I need to implement this myself?
Thanks in advance!

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evhen, 2016-08-30
@mitaichik

1st option: Don't use a mutable object, but every time you want to change something, create a new object, while the object itself must be immutable . Access to object to carry out through factory. This solution is the most correct IMHO .
immutable class

public final class User {

  private final String login;
  private final Date dateCreate;
  private final String description;
  private final Set<String> roles;

  public User(String login, Date dateCreate, String description, Set<String> roles) {
    this.login = login;
    this.dateCreate = (Date) dateCreate.clone();
    this.description = description;
    this.roles = Collections.unmodifiableSet(roles);
  }

  public String getLogin() {
    return login;
  }

  public Date getDateCreate() {
    return (Date) dateCreate.clone();
  }

  public String getDescription() {
    return description;
  }

  public Set<String> getRoles() {
    return roles;
  }
}

Factory
public class UserFactory<T> {

  private final AtomicReference<T> atomicReference;

  public UserFactory(T object) {
    this.atomicReference = new AtomicReference<>(object);
  }

  public T getObject() {
    return atomicReference.get();
  }

  public void setObject(T object) {
    atomicReference.set(object);
  }
}

public static void main(String[] args) {

    User user = new User("user1", new Date(), "test user", new HashSet<>(Arrays.asList("READ", "ADD")));

    UserFactory<User> userFactory = new UserFactory<>(user);

    exampleUsingUser(userFactory);

  }

  public static void exampleUsingUser(UserFactory<User> userFactory) {

    User user = userFactory.getObject();

    System.out.println(user.getLogin());
    System.out.println(user.getDescription());
    System.out.println(user.getRoles());
  }

First we need to allocate a class interface whose object state will change
public interface Settings {

  String getColor();
  void setColor(String color);

  String getDescription();
  void setDescription(String description);

  int getSize();
  void setSize(int size);
}

Implementing the interface
public class SettingsImpl implements Settings {

  private volatile String color;
  private volatile String description;
  private volatile int size;


  public static Settings newSettings() {
    return ProxySettingsKeeper.createProxy(new SettingsImpl());
  }
  
  private SettingsImpl() {
  }

  @Override
  public String getColor() {
    return color;
  }

  @Override
  public void setColor(String color) {
    this.color = color;
  }

  @Override
  public String getDescription() {
    return description;
  }

  @Override
  public void setDescription(String description) {
    this.description = description;
  }

  @Override
  public int getSize() {
    return size;
  }

  @Override
  public void setSize(int size) {
    this.size = size;
  }
}

Proxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ProxySettingsKeeper implements InvocationHandler {

  private final Settings settings;

  private final ReentrantReadWriteLock.ReadLock readLock;
  private final ReentrantReadWriteLock.WriteLock writeLock;

  public ProxySettingsKeeper(Settings settings) {

    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    this.readLock = readWriteLock.readLock();
    this.writeLock = readWriteLock.writeLock();

    this.settings = settings;
  }

  public static Settings createProxy(Settings settings) {
    return (Settings) Proxy.newProxyInstance(settings.getClass().getClassLoader()
        , new Class[]{Settings.class}
        , new ProxySettingsKeeper(settings));
  }


  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    String name = method.getName();

    if (name.startsWith("get")) {

      readLock.lock();
      try {
        return method.invoke(settings, args);
      } finally {
        readLock.unlock();
      }

    } else if (name.startsWith("set")) {

      writeLock.lock();
      try {
        return method.invoke(settings, args);
      } finally {
        writeLock.unlock();
      }
    }

    return method.invoke(settings, args);
  }
}

public static void main(String[] args) {

    Settings settings = SettingsImpl.newSettings();

    settings.setDescription("test");

    System.out.println(settings.getDescription());
  }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question