Search in sources :

Example 6 with FlushMode

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);
            }
        }
    }
}
Also used : CartOperationRequest(org.broadleafcommerce.core.order.service.workflow.CartOperationRequest) OrderItemRequestDTO(org.broadleafcommerce.core.order.service.call.OrderItemRequestDTO) FlushMode(org.hibernate.FlushMode) Session(org.hibernate.Session)

Example 7 with FlushMode

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));
    }
}
Also used : Order(org.broadleafcommerce.core.order.domain.Order) WorkflowException(org.broadleafcommerce.core.workflow.WorkflowException) ArrayList(java.util.ArrayList) ActivityMessageDTO(org.broadleafcommerce.core.order.service.call.ActivityMessageDTO) UpdateCartException(org.broadleafcommerce.core.order.service.exception.UpdateCartException) FlushMode(org.hibernate.FlushMode) CartOperationRequest(org.broadleafcommerce.core.order.service.workflow.CartOperationRequest) OrderItem(org.broadleafcommerce.core.order.domain.OrderItem) DiscreteOrderItem(org.broadleafcommerce.core.order.domain.DiscreteOrderItem) GiftWrapOrderItem(org.broadleafcommerce.core.order.domain.GiftWrapOrderItem) BundleOrderItem(org.broadleafcommerce.core.order.domain.BundleOrderItem) AddToCartException(org.broadleafcommerce.core.order.service.exception.AddToCartException) RemoveFromCartException(org.broadleafcommerce.core.order.service.exception.RemoveFromCartException) Session(org.hibernate.Session) Transactional(org.springframework.transaction.annotation.Transactional)

Example 8 with FlushMode

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;
}
Also used : PricingException(org.broadleafcommerce.core.pricing.service.exception.PricingException) TransactionStatus(org.springframework.transaction.TransactionStatus) FlushMode(org.hibernate.FlushMode) WorkflowException(org.broadleafcommerce.core.workflow.WorkflowException) IllegalCartOperationException(org.broadleafcommerce.core.order.service.exception.IllegalCartOperationException) OfferException(org.broadleafcommerce.core.offer.service.exception.OfferException) OfferAlreadyAddedException(org.broadleafcommerce.core.offer.service.exception.OfferAlreadyAddedException) ItemNotFoundException(org.broadleafcommerce.core.order.service.exception.ItemNotFoundException) LockAcquisitionException(org.hibernate.exception.LockAcquisitionException) AddToCartException(org.broadleafcommerce.core.order.service.exception.AddToCartException) OfferMaxUseExceededException(org.broadleafcommerce.core.offer.service.exception.OfferMaxUseExceededException) UpdateCartException(org.broadleafcommerce.core.order.service.exception.UpdateCartException) PricingException(org.broadleafcommerce.core.pricing.service.exception.PricingException) OfferExpiredException(org.broadleafcommerce.core.offer.service.exception.OfferExpiredException) RemoveFromCartException(org.broadleafcommerce.core.order.service.exception.RemoveFromCartException) Session(org.hibernate.Session) LockAcquisitionException(org.hibernate.exception.LockAcquisitionException)

Example 9 with FlushMode

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);
    }
}
Also used : CannotCreateTransactionException(org.springframework.transaction.CannotCreateTransactionException) IllegalTransactionStateException(org.springframework.transaction.IllegalTransactionStateException) Connection(java.sql.Connection) InvalidIsolationLevelException(org.springframework.transaction.InvalidIsolationLevelException) FlushMode(org.hibernate.FlushMode) ConnectionHolder(org.springframework.jdbc.datasource.ConnectionHolder) Transaction(org.hibernate.Transaction) SessionImplementor(org.hibernate.engine.spi.SessionImplementor) Interceptor(org.hibernate.Interceptor) Session(org.hibernate.Session)

Example 10 with FlushMode

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);
}
Also used : Connection(java.sql.Connection) InvalidIsolationLevelException(org.springframework.transaction.InvalidIsolationLevelException) FlushMode(org.hibernate.FlushMode) Session(org.hibernate.Session)

Aggregations

FlushMode (org.hibernate.FlushMode)19 Session (org.hibernate.Session)13 CartOperationRequest (org.broadleafcommerce.core.order.service.workflow.CartOperationRequest)4 Transactional (org.springframework.transaction.annotation.Transactional)4 UpdateCartException (org.broadleafcommerce.core.order.service.exception.UpdateCartException)3 WorkflowException (org.broadleafcommerce.core.workflow.WorkflowException)3 SQLQuery (org.hibernate.SQLQuery)3 Connection (java.sql.Connection)2 ArrayList (java.util.ArrayList)2 Order (org.broadleafcommerce.core.order.domain.Order)2 OrderItemRequestDTO (org.broadleafcommerce.core.order.service.call.OrderItemRequestDTO)2 AddToCartException (org.broadleafcommerce.core.order.service.exception.AddToCartException)2 RemoveFromCartException (org.broadleafcommerce.core.order.service.exception.RemoveFromCartException)2 SessionImplementor (org.hibernate.engine.spi.SessionImplementor)2 Serializable (java.io.Serializable)1 Field (java.lang.reflect.Field)1 Date (java.util.Date)1 SystemException (javax.transaction.SystemException)1 AdminMainEntity (org.broadleafcommerce.common.admin.domain.AdminMainEntity)1 OfferAlreadyAddedException (org.broadleafcommerce.core.offer.service.exception.OfferAlreadyAddedException)1