JPA: bloqueo al realizar una inserción indirecta

Estoy escribiendo un software que rastrea el uso de medicamentos. Estoy usando JPA para interactuar con la base de datos. Mi modelo consta de dos entidades: unaPrescription y unDose. CadaPrescription tiene una colección deDose casos que representan las dosis administradas al paciente como parte de esta receta de la siguiente manera:

Prescription.java

@Entity
@XmlRootElement
public class Prescription {

    private long id;
    private Collection<Dose> doses = new ArrayList<Dose>();
    /**
     * Versioning field used by JPA to track concurrent changes.
     */
    private long version;
    // Other properties omitted...

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    // We specify cascade such that when we modify this collection, it will propagate to the DOSE table (e.g. when
    // adding a new dose to this collection, a corresponding record will be created in the DOSE table).
    @OneToMany(mappedBy = "prescription", cascade = CascadeType.ALL)
    public Collection<Dose> getDoses() {
        // todo update to list or collection interface.
        return doses;
    }

    public void setDoses(Collection<Dose> doses) {
        this.doses = doses;
    }

    @Version
    public long getVersion() {
        return version;
    }

    /**
     * Application code should not call this method. However, it must be present for JPA to function.
     * @param version
     */
    public void setVersion(long version) {
        this.version = version;
    }
}

Dose.java

@Entity
@XmlRootElement
public class Dose {

    private long id;
    private Prescription prescription;
    // Other properties omitted...

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @XmlTransient
    @ManyToOne
    @JoinColumn(name = "PRESCRIPTION_ID") // Specifies name of column pointing back to the parent prescription.
    public Prescription getPrescription() {
        return prescription;
    }

    public void setPrescription(Prescription prescription) {
        this.prescription = prescription;
    }

}

A Dose solo puede existir en el contexto de unPrescriptiony, por lo tanto, unDose se inserta en la base de datos indirectamente agregándolo a la colección de dosis de su receta:

DoseService.java

@Stateless
public class DoseService {

    @PersistenceContext(unitName = "PrescriptionUnit")
    private EntityManager entityMgr;

    /**
     * Insert a new dose for a given prescription ID.
     * @param prescriptionId The prescription ID.
     * @return The inserted {@code Dose} instance if insertion was successful,
     * or {@code null} if insertion failed (if there is currently no doses available for the given prescription ID).
     */
    @TransactionAttribute(value = TransactionAttributeType.REQUIRED)
    public Dose addDose(long prescriptionId) {
        // Find the prescription.
        Prescription p = entityMgr.find(Prescription.class, prescriptionId);
        if (p == null) {
            // Invalid prescription ID.
            throw new IllegalArgumentException("Prescription with id " + prescriptionId + " does not exist.");
        }
        // TODO is this sufficient locking?
        entityMgr.lock(p, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
        Dose d = null;
        if (isDoseAvailable(p)) {
            // A dose is available, create it and insert it into the database.
            d = new Dose();
            // Setup the link between the new dose and its parent prescription.
            d.setPrescription(p);
            p.getDoses().add(d);
        }
        try {
            // Flush changes to database.
            entityMgr.flush();
            return d;
        } catch (OptimisticLockException ole) {
            // Rethrow application-managed exception to ensure that caller will have a chance of detecting failure due to concurrent updates.
            // (OptimisticLockExceptions can be swallowed by the container)
            // See "Recovering from Optimistic Failures" (page 365) in "Pro JPA 2" by M. Keith and M. Schincariol for details.
            throw new ChangeCollisionException();
        }
    }


    /**
     * Checks if a dose is available for a given prescription.
     * @param p The prescription for which to look up if a dose is available.
     * @return {@code true} if a dose is available, {@code false} otherwise.
     */
    @TransactionAttribute(value = TransactionAttributeType.MANDATORY)
    private boolean isDoseAvailable(Prescription p) {
        // Business logic that inspects p.getDoses() and decides if it is safe to give the patient a dose at this time.
    }

}

addDose(long) Se puede llamar simultáneamente. Al decidir si hay una dosis disponible, la lógica empresarial inspecciona la colección de dosis de la receta. La transacción debería fallar si esta colección se modifica simultáneamente (por ejemplo, mediante una llamada simultánea aaddDose(long)) Yo uso elLockModeType.OPTIMISTIC_FORCE_INCREMENT para lograr esto (en lugar de adquirir un bloqueo de tabla en la tabla de DOSIS). EnPro JPA 2 por Keith y Schincariol He leído eso:

El bloqueo de escritura garantiza todo lo que hace el bloqueo de lectura optimista, pero también se compromete a incrementar el campo de versión en la transacción, independientemente de si un usuario actualizó la entidad o no. [...] el caso común para usar OPTIMISTIC_FORCE_INCREMENT es garantizar la coherencia entre los cambios de relación de la entidad (a menudo son relaciones de uno a muchos con claves externas de destino) cuando en el modelo de objetos cambian los punteros de relación de la entidad, pero en el modelo de datos ninguna columna en la tabla de entidad cambia.

¿Es correcto mi comprensión de este modo de bloqueo? ¿Mi estrategia actual garantiza que eladdDose la transacción fallará si hay CUALQUIER cambio en la colección de dosis de la receta (ya sea agregar, eliminar o actualizar cualquier dosis en la colección)?

Respuestas a la pregunta(2)

Su respuesta a la pregunta