use of org.hibernate.FlushMode in project BroadleafCommerce by BroadleafCommerce.
the class OrderServiceImpl method addChildItems.
@Override
public void addChildItems(OrderItemRequestDTO orderItemRequestDTO, int numAdditionRequests, int currentAddition, ProcessContext<CartOperationRequest> context, List<ActivityMessageDTO> orderMessages) throws WorkflowException {
if (CollectionUtils.isNotEmpty(orderItemRequestDTO.getChildOrderItems())) {
Long parentOrderItemId = context.getSeedData().getOrderItem().getId();
for (OrderItemRequestDTO childRequest : orderItemRequestDTO.getChildOrderItems()) {
childRequest.setParentOrderItemId(parentOrderItemId);
currentAddition++;
if (childRequest.getQuantity() > 0) {
CartOperationRequest childCartOpRequest = new CartOperationRequest(context.getSeedData().getOrder(), childRequest, currentAddition == numAdditionRequests);
Session session = em.unwrap(Session.class);
FlushMode current = session.getFlushMode();
if (!autoFlushAddToCart) {
// Performance measure. Hibernate will sometimes perform an autoflush when performing query operations and this can
// be expensive. It is possible to avoid the autoflush if there's no concern about queries in the flow returning
// incorrect results because something has not been flushed to the database yet.
session.setFlushMode(FlushMode.MANUAL);
}
ProcessContext<CartOperationRequest> childContext;
try {
childContext = (ProcessContext<CartOperationRequest>) addItemWorkflow.doActivities(childCartOpRequest);
} finally {
if (!autoFlushAddToCart) {
session.setFlushMode(current);
}
}
orderMessages.addAll(((ActivityMessages) childContext).getActivityMessages());
addChildItems(childRequest, numAdditionRequests, currentAddition, childContext, orderMessages);
}
}
}
}
use of org.hibernate.FlushMode in project BroadleafCommerce by BroadleafCommerce.
the class OrderServiceImpl method addItemWithPriceOverrides.
@Override
@Transactional(value = "blTransactionManager", rollbackFor = { AddToCartException.class })
public Order addItemWithPriceOverrides(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder) throws AddToCartException {
Order order = findOrderById(orderId);
preValidateCartOperation(order);
if (getAutomaticallyMergeLikeItems()) {
OrderItem item = findMatchingItem(order, orderItemRequestDTO);
if (item != null && item.getParentOrderItem() == null) {
orderItemRequestDTO.setQuantity(item.getQuantity() + orderItemRequestDTO.getQuantity());
orderItemRequestDTO.setOrderItemId(item.getId());
try {
return updateItemQuantity(orderId, orderItemRequestDTO, priceOrder);
} catch (RemoveFromCartException e) {
throw new AddToCartException("Unexpected error - system tried to remove item while adding to cart", e);
} catch (UpdateCartException e) {
throw new AddToCartException("Could not update quantity for matched item", e);
}
}
}
try {
// We only want to price on the last addition for performance reasons and only if the user asked for it.
int numAdditionRequests = priceOrder ? (getTotalChildOrderItems(orderItemRequestDTO)) : -1;
int currentAddition = 1;
CartOperationRequest cartOpRequest = new CartOperationRequest(findOrderById(orderId), orderItemRequestDTO, currentAddition == numAdditionRequests);
Session session = em.unwrap(Session.class);
FlushMode current = session.getFlushMode();
if (!autoFlushAddToCart) {
// Performance measure. Hibernate will sometimes perform an autoflush when performing query operations and this can
// be expensive. It is possible to avoid the autoflush if there's no concern about queries in the flow returning
// incorrect results because something has not been flushed to the database yet.
session.setFlushMode(FlushMode.MANUAL);
}
ProcessContext<CartOperationRequest> context;
try {
context = (ProcessContext<CartOperationRequest>) addItemWorkflow.doActivities(cartOpRequest);
} finally {
if (!autoFlushAddToCart) {
session.setFlushMode(current);
}
}
List<ActivityMessageDTO> orderMessages = new ArrayList<ActivityMessageDTO>();
orderMessages.addAll(((ActivityMessages) context).getActivityMessages());
// Update the orderItemRequest incase it changed during the initial add to cart workflow
orderItemRequestDTO = context.getSeedData().getItemRequest();
numAdditionRequests = priceOrder ? (getTotalChildOrderItems(orderItemRequestDTO) - 1) : -1;
addChildItems(orderItemRequestDTO, numAdditionRequests, currentAddition, context, orderMessages);
context.getSeedData().getOrder().setOrderMessages(orderMessages);
return context.getSeedData().getOrder();
} catch (WorkflowException e) {
throw new AddToCartException("Could not add to cart", getCartOperationExceptionRootCause(e));
}
}
use of org.hibernate.FlushMode in project BroadleafCommerce by BroadleafCommerce.
the class OrderServiceImpl method save.
@Override
public Order save(Order order, Boolean priceOrder) throws PricingException {
// persist the order first
TransactionStatus status = TransactionUtils.createTransaction("saveOrder", TransactionDefinition.PROPAGATION_REQUIRED, transactionManager);
try {
order = persist(order);
TransactionUtils.finalizeTransaction(status, transactionManager, false);
} catch (RuntimeException ex) {
TransactionUtils.finalizeTransaction(status, transactionManager, true);
throw ex;
}
// make any pricing changes - possibly retrying with the persisted state if there's a lock failure
if (priceOrder) {
int retryCount = 0;
boolean isValid = false;
while (!isValid) {
Session session = em.unwrap(Session.class);
FlushMode current = session.getFlushMode();
try {
if (!autoFlushSaveCart) {
// Performance measure. Hibernate will sometimes perform an autoflush when performing query operations and this can
// be expensive. It is possible to avoid the autoflush if there's no concern about queries in the flow returning
// incorrect results because something has not been flushed to the database yet.
session.setFlushMode(FlushMode.MANUAL);
}
order = pricingService.executePricing(order);
isValid = true;
} catch (Exception ex) {
boolean isValidCause = false;
Throwable cause = ex;
while (!isValidCause) {
if (cause.getClass().equals(LockAcquisitionException.class)) {
isValidCause = true;
}
cause = cause.getCause();
if (cause == null) {
break;
}
}
if (isValidCause) {
if (LOG.isInfoEnabled()) {
LOG.info("Problem acquiring lock during pricing call - attempting to price again.");
}
isValid = false;
if (retryCount >= pricingRetryCountForLockFailure) {
if (LOG.isInfoEnabled()) {
LOG.info("Problem acquiring lock during pricing call. Retry limit exceeded at (" + retryCount + "). Throwing exception.");
}
if (ex instanceof PricingException) {
throw (PricingException) ex;
} else {
throw new PricingException(ex);
}
} else {
order = findOrderById(order.getId());
retryCount++;
}
try {
Thread.sleep(pricingRetryWaitIntervalForLockFailure);
} catch (Throwable e) {
// do nothing
}
} else {
if (ex instanceof PricingException) {
throw (PricingException) ex;
} else {
throw new PricingException(ex);
}
}
} finally {
if (!autoFlushSaveCart) {
session.setFlushMode(current);
}
}
}
// make the final save of the priced order
status = TransactionUtils.createTransaction("saveOrder", TransactionDefinition.PROPAGATION_REQUIRED, transactionManager);
Session session = em.unwrap(Session.class);
FlushMode current = session.getFlushMode();
try {
if (!autoFlushSaveCart) {
// Performance measure. Hibernate will sometimes perform an autoflush when performing query operations and this can
// be expensive. It is possible to avoid the autoflush if there's no concern about queries in the flow returning
// incorrect results because something has not been flushed to the database yet.
session.setFlushMode(FlushMode.MANUAL);
}
order = persist(order);
if (extensionManager != null) {
extensionManager.getProxy().attachAdditionalDataToOrder(order, priceOrder);
}
if (!autoFlushSaveCart) {
session.setFlushMode(current);
}
TransactionUtils.finalizeTransaction(status, transactionManager, false);
} catch (RuntimeException ex) {
TransactionUtils.finalizeTransaction(status, transactionManager, true);
throw ex;
} finally {
if (!autoFlushSaveCart && !session.getFlushMode().equals(current)) {
session.setFlushMode(current);
}
}
}
return order;
}
use of org.hibernate.FlushMode in project spring-framework by spring-projects.
the class HibernateTransactionManager method doBegin.
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException("Pre-bound JDBC Connection found! HibernateTransactionManager does not support " + "running within DataSourceTransactionManager if told to manage the DataSource itself. " + "It is recommended to use a single HibernateTransactionManager for all transactions " + "on a single DataSource, no matter whether Hibernate or JDBC access.");
}
SessionImplementor session = null;
try {
if (!txObject.hasSessionHolder() || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();
Session newSession = (entityInterceptor != null ? obtainSessionFactory().withOptions().interceptor(entityInterceptor).openSession() : obtainSessionFactory().openSession());
if (this.sessionInitializer != null) {
this.sessionInitializer.accept(newSession);
}
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
}
txObject.setSession(newSession);
}
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
}
Connection con = session.connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
int currentHoldability = con.getHoldability();
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
txObject.setPreviousHoldability(currentHoldability);
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
}
txObject.connectionPrepared();
} else {
// Not allowed to change the transaction settings of the JDBC Connection.
if (isolationLevelNeeded) {
// We should set a specific isolation level but are not allowed to...
throw new InvalidIsolationLevelException("HibernateTransactionManager is not allowed to support custom isolation levels: " + "make sure that its 'prepareConnection' flag is on (the default) and that the " + "Hibernate connection release mode is set to ON_CLOSE.");
}
if (logger.isDebugEnabled()) {
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
}
}
}
if (definition.isReadOnly() && txObject.isNewSession()) {
// Just set to MANUAL in case of a new Session for this transaction.
session.setHibernateFlushMode(FlushMode.MANUAL);
// As of 5.1, we're also setting Hibernate's read-only entity mode by default.
session.setDefaultReadOnly(true);
}
if (!definition.isReadOnly() && !txObject.isNewSession()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getHibernateFlushMode();
if (FlushMode.MANUAL.equals(flushMode)) {
session.setHibernateFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
}
Transaction hibTx;
// Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
// Applies to all statements, also to inserts, updates and deletes!
hibTx = session.getTransaction();
hibTx.setTimeout(timeout);
hibTx.begin();
} else {
// Open a plain Hibernate transaction without specified timeout.
hibTx = session.beginTransaction();
}
// Add the Hibernate transaction to the session holder.
txObject.getSessionHolder().setTransaction(hibTx);
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
ConnectionHolder conHolder = new ConnectionHolder(session::connection);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC [" + conHolder.getConnectionHandle() + "]");
}
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
txObject.setConnectionHolder(conHolder);
}
// Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.bindResource(obtainSessionFactory(), txObject.getSessionHolder());
}
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
} catch (Throwable ex) {
if (txObject.isNewSession()) {
try {
if (session != null && session.getTransaction().getStatus() == TransactionStatus.ACTIVE) {
session.getTransaction().rollback();
}
} catch (Throwable ex2) {
logger.debug("Could not rollback Session after failed transaction begin", ex);
} finally {
SessionFactoryUtils.closeSession(session);
txObject.setSessionHolder(null);
}
}
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
}
}
use of org.hibernate.FlushMode in project spring-framework by spring-projects.
the class HibernateJpaDialect method beginTransaction.
@Override
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) throws PersistenceException, SQLException, TransactionException {
Session session = getSession(entityManager);
if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
session.getTransaction().setTimeout(definition.getTimeout());
}
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
Integer previousIsolationLevel = null;
Connection preparedCon = null;
if (isolationLevelNeeded || definition.isReadOnly()) {
if (this.prepareConnection) {
preparedCon = HibernateConnectionHandle.doGetConnection(session);
previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(preparedCon, definition);
} else if (isolationLevelNeeded) {
throw new InvalidIsolationLevelException(getClass().getSimpleName() + " does not support custom isolation levels since the 'prepareConnection' flag is off.");
}
}
// Standard JPA transaction begin call for full JPA context setup...
entityManager.getTransaction().begin();
// Adapt flush mode and store previous isolation level, if any.
FlushMode previousFlushMode = prepareFlushMode(session, definition.isReadOnly());
return new SessionTransactionData(session, previousFlushMode, preparedCon, previousIsolationLevel);
}
Aggregations