2012-06-25 2 views
0

Я задал аналогичный вопрос на форуме Code Review, но мне было предложено задать этот вопрос здесь. Меня интересует ключевое слово synchronized в веб-методе ниже. Поскольку setPerson вызывается из пула потоков (что означает, что могут быть вызваны разные потоки), я должен каким-то образом синхронизировать его. Пул thead используется EclipseLink, когда мой клиент делает SOAP-вызовы методу. Мой вопрос в том, является ли хорошей практикой создание веб-метода synchronized или я могу выполнить синхронизацию с em.lock(person, WRITE)?Хорошая практика для синхронизации веб-метода при использовании разных потоков?

@Override 
public synchronized void setPerson(Person person) { 
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersonLibPU");    
    EntityManager em = emf.createEntityManager(); 
    if(!em.getTransaction().isActive()) { 
     em.getTransaction().begin(); 
    } 
    try { 
     person.setPersonId(getLastInsertedId() + 1); // Get the last inserted ID and increment it by 1 
     em.merge(person); 
     em.getTransaction().commit(); 
     emf.getCache().evict(Person.class);      
    } catch (Exception ex) { 
     if(em.getTransaction().isActive()) 
      em.getTransaction().rollback(); 
    } finally { 
     em.close(); 
    } 
} 

РЕДАКТИРОВАТЬ
Я добавил еще одну строку в приведенной выше, где я установить значение первичного ключа объекта кода человека. Для этого синхронизация выполняется, а не для каких-либо общих объектов Java. Мне нужно синхронизировать его, чтобы два потока не могли получить один и тот же первичный ключ.

+3

Код использует только локальные переменные. Почему вы хотите синхронизировать его. Сторона не: вы не должны создавать новый EntityManagerFactory в каждом методе. Создайте его один раз и всегда используйте уникальный экземпляр. –

+0

Да, переменные являются локальными, но это транзакция базы данных, которую я боюсь. Два или более потока могут потенциально вызывать setPerson() и записывать один и тот же первичный ключ, поскольку PK: s не увеличиваются автоматически. Таким образом, синхронизация не для общего объекта Java, а для доступа к базе данных. – Rox

+1

Тогда вам понадобится обработать эту возможность, обработав потенциальное исключение, которое может быть выбрано. Синхронизация не является правильным решением, поскольку она не будет обрабатывать случай, когда человек будет сохранен другим методом, или человек будет сохранен другим приложением или человек будет сохранен другой JVM в кластере. –

ответ

1

Возможно, вы задаете неправильный вопрос. Синхронизация вам не поможет, так как единственная часть, которая имеет проблемы с параллелизмом, - это getLastInsertedId(): вы не хотите, чтобы два метода могли получить одно и то же значение и попытаться сохранить экземпляр с этим идентификатором.

Синхронизация setPerson решает проблему только в том случае, если это единственный метод, который сохраняется в памяти Person.

Если возможно, используйте функциональные возможности автоматического прироста хранилища данных; если это решение ORM выполняет контекстное распределение идентификаторов? В последнем случае было бы иметь способ getNextId, чтобы мог синхронизировать и возвращать добавочное значение. Это может привести к несмежным последовательностям идентификаторов в базе данных (getNextId не будет знать, успешно ли выполнялась операция persist), но это уменьшает объем блокировки.

Как указывает JB Nizet, выделение идентификатора необходимо сохранить и сделать доступным в некотором роде, доступном для всех клиентов этого хранилища данных. Если у вас есть два экземпляра вашего приложения, которые сохраняют экземпляры Person, вам необходимо убедиться, что они имеют общий идентификатор.

Смежные вопросы