EntityManager.merge () не создает запись таблицы - PullRequest
0 голосов
/ 07 июля 2011

Следующий код не может надежно создать новую запись.

TransferRecord transfer = new TransferRecord();
transfer.setTransferId(metaData.getTransferId());
transfer.setUserName(metaData.getUserId().getUserName());
transfer.setCancelled(false);
em.merge(transfer);
em.flush();

Вот код для записи передачи:

/***
 * Contains a record of an ongoing transfer.
 * @author anchapma
 *
 */
@Entity
@Table(name = "TransferRecord")
public class TransferRecord implements Serializable
{
    /**
     * Generated static unique ID.
     */
    private static final long serialVersionUID = -8131586518447878482L;

    /***
     * The id of the transfer.
     */
    private String transferId;

    /***
     * The name of the user who ownes the transfer.
     */
    private String username;

    /***
     * Has this transfer been cancelled?
     */
    private boolean cancelled;

    /***
     * Constructor.
     */
    public TransferRecord()
    {
        this.transferId = "";
        this.username = "";
        this.cancelled = false;
    }

    /***
     * Gets the transfer ID.
     * 
     * @return The transfer ID.
     */
    @Id
    @Column(name = "TransferID", unique = true, nullable = false, length = 50)
    public String getTransferId()
    {
        return this.transferId;
    }

    /***
     * Sets the transfer ID.
     * @param transferId The new transfer ID.
     */
    public void setTransferId(String transferId)
    {
        this.transferId = transferId;
    }

    /***
     * Gets the username.
     * 
     * @return The username.
     */
    @Column(name = "UserName", nullable = false, length = 50)
    public String getUserName()
    {
        return this.username;
    }

    /***
     * Sets the username.
     * @param username The new username.
     */
    public void setUserName(String username)
    {
        this.username = username;
    }

    /***
     * Gets whether or not the transfer has been cancelled.
     * 
     * @return True if the transfer has been cancelled.
     */
    @Column(name = "Cancelled", nullable = false, length = 50)
    public boolean getCancelled()
    {
        return this.cancelled;
    }

    /***
     * Sets whether or not the transfer has been cancelled.
     * @param cancelled True if the transfer has been cancelled.
     */
    public void setCancelled(boolean cancelled)
    {
        this.cancelled = cancelled;
    }
}

Я думаю, что происходит то, что запись добавляется в базу данных после задержки. Мой код использует наличие или отсутствие записи TransferRecord в качестве флага. Поэтому необходимо, чтобы данные немедленно отображались в таблице.

Вероятно, я прав в своем предположении? Если да, есть ли способ заставить вызов em.flush() ждать, пока он не записал запись, прежде чем вернуться?

1 Ответ

1 голос
/ 07 июля 2011

В сопроводительном комментарии к вопросу говорится -

«Вызывающий компонент не имеет состояния и выполняется в течение многих секунд. Данные не отображаются другим пользователям базы данных до тех пор, пока не завершится работа компонента».

Это описанное поведение не имеет ничего общего с очисткой контекста постоянства, связанного с EntityManager.Это во многом связано с уровнем изоляции транзакции, связанной с транзакцией.Транзакция, связанная с сессионным компонентом без сохранения состояния (SLSB), фактически фиксирует данные в базе данных, только при возврате из метода bean-компонента, поскольку каждый метод SLSB может быть связан с атрибутом транзакции по умолчанию REQUIRED (который использует существующую транзакцию или запускается).новенький);В результате получается, что транзакция завершается с помощью отката в методе SLSB или с помощью коммита при возврате из метода.

Это поведение влияет на операции чтения, выполняемые другими клиентами и транзакциями, поскольку итоговый результат зависит от изоляции.уровень текущей соответствующей транзакции, который, в свою очередь, зависит от уровня изоляции, указанного в пуле соединений с базой данных.Для большинства баз данных и связанных пулов соединений уровень изоляции транзакции составляет READ COMMITTED, и поэтому другие транзакции могут читать только данные, зафиксированные соответствующей транзакцией (т.е. при возврате метода SLSB).Это желательное поведение в большинстве случаев, поскольку вы не хотите читать данные, которые не были переданы (и впоследствии могут быть откатаны), что может привести к грязному чтению.

Если вы намереваетесь выполнить грязное чтение,Вы должны сконфигурировать пул соединений JDBC, чтобы разрешить грязное чтение, или, другими словами, установить уровень изоляции транзакции для пула READ UNCOMMITTED.Изменения конфигурации будут варьироваться от контейнера к контейнеру, а также будут зависеть от поддержки уровня изоляции READ UNCOMMITTED базой данных;Например, Oracle не позволяет вам установить уровень изоляции READ UNCOMMITTED и может установить для него следующий более высокий уровень изоляции, поддерживаемый им (READ COMMITTED).

Если вы хотите избежать обмана вокругс уровнями изоляции транзакций рассмотрите возможность разделения вызовов методов на несколько транзакций.Этого можно добиться, создав новый бизнес-метод в отдельной SLSB, который требует создания новой транзакции при каждом вызове (REQUIRES_NEW).Пример псевдокода описан ниже:

@Stateless
@Local(X.class)
public class SLSBX implements X {

    @EJB Y y;

    @TransactionAttribute(TransactionAttributeType.REQUIRED) // start a new transaction to do work
    public void sampleMethod() {
         // suspends the existing transaction on invoking Y.anotherSampleMethod()
         Y.anotherSampleMethod();
         // continue doing work in the current transaction. Work done in anotherSampleMethod() would have either committed or rolled back.
    }
}

@Stateless
@Local(Y.class)
public class SLSBY implements Y {
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) // Suspends the existing transaction and creates a new transaction that terminates on method return
    public void anotherSampleMethod() {
        // do some stuff
    }
}

Этот подход, конечно, рекомендуется, только если деловая природа транзакции допускает принятие такого подхода.Как правило, все реальные бизнес-операции, являющиеся частью бизнес-транзакции, необходимо включить в реальную транзакцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...