Search in sources :

Example 86 with SessionImplementor

use of org.hibernate.engine.spi.SessionImplementor in project hibernate-orm by hibernate.

the class BatchingBatchFailureTest method testBasicInsertion.

@Test
public void testBasicInsertion() {
    Session session = openSession();
    session.getTransaction().begin();
    try {
        session.persist(new User(1, "ok"));
        session.persist(new User(2, null));
        session.persist(new User(3, "ok"));
        session.persist(new User(4, "ok"));
        session.persist(new User(5, "ok"));
        session.persist(new User(6, "ok"));
        // the flush should fail
        session.flush();
        fail("Expecting failed flush");
    } catch (Exception expected) {
        System.out.println("Caught expected exception : " + expected);
        expected.printStackTrace(System.out);
        try {
            // at this point the transaction is still active but the batch should have been aborted (have to use reflection to get at the field)
            SessionImplementor sessionImplementor = (SessionImplementor) session;
            Field field = sessionImplementor.getJdbcCoordinator().getClass().getDeclaredField("currentBatch");
            field.setAccessible(true);
            Batch batch = (Batch) field.get(sessionImplementor.getJdbcCoordinator());
            if (batch == null) {
                throw new Exception("Current batch was null");
            } else {
                // make sure it's actually a batching impl
                assertEquals(BatchingBatch.class, batch.getClass());
                field = AbstractBatchImpl.class.getDeclaredField("statements");
                field.setAccessible(true);
                // check to see that there aren't any statements queued up (this can be an issue if using SavePoints)
                assertEquals(0, ((Map) field.get(batch)).size());
            }
        } catch (Exception fieldException) {
            fail("Couldn't inspect field " + fieldException.getMessage());
        }
    } finally {
        session.getTransaction().rollback();
        session.close();
    }
}
Also used : Field(java.lang.reflect.Field) Batch(org.hibernate.engine.jdbc.batch.spi.Batch) BatchingBatch(org.hibernate.engine.jdbc.batch.internal.BatchingBatch) SessionImplementor(org.hibernate.engine.spi.SessionImplementor) BatchingBatch(org.hibernate.engine.jdbc.batch.internal.BatchingBatch) Map(java.util.Map) Session(org.hibernate.Session) Test(org.junit.Test)

Example 87 with SessionImplementor

use of org.hibernate.engine.spi.SessionImplementor in project hibernate-orm by hibernate.

the class NonBatchingBatchFailureTest method testBasicInsertion.

@Test
public void testBasicInsertion() {
    Session session = openSession();
    session.getTransaction().begin();
    try {
        session.persist(new User(1, "ok"));
        session.persist(new User(2, null));
        session.persist(new User(3, "ok"));
        // the flush should fail
        session.flush();
        fail("Expecting failed flush");
    } catch (Exception expected) {
        System.out.println("Caught expected exception : " + expected);
        expected.printStackTrace(System.out);
        try {
            // at this point the transaction is still active but the batch should have been aborted (have to use reflection to get at the field)
            SessionImplementor sessionImplementor = (SessionImplementor) session;
            Field field = sessionImplementor.getJdbcCoordinator().getClass().getDeclaredField("currentBatch");
            field.setAccessible(true);
            Batch batch = (Batch) field.get(sessionImplementor.getJdbcCoordinator());
            if (batch != null) {
                // make sure it's actually a batching impl
                assertEquals(NonBatchingBatch.class, batch.getClass());
                field = AbstractBatchImpl.class.getDeclaredField("statements");
                field.setAccessible(true);
                // check to see that there aren't any statements queued up (this can be an issue if using SavePoints)
                assertEquals(0, ((Map) field.get(batch)).size());
            }
        } catch (Exception fieldException) {
            fail("Couldn't inspect field " + fieldException.getMessage());
        }
    } finally {
        session.getTransaction().rollback();
        session.close();
    }
}
Also used : Field(java.lang.reflect.Field) NonBatchingBatch(org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch) Batch(org.hibernate.engine.jdbc.batch.spi.Batch) SessionImplementor(org.hibernate.engine.spi.SessionImplementor) NonBatchingBatch(org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch) Map(java.util.Map) Session(org.hibernate.Session) Test(org.junit.Test)

Example 88 with SessionImplementor

use of org.hibernate.engine.spi.SessionImplementor in project hibernate-orm by hibernate.

the class ValidityAuditStrategy method perform.

@Override
public void perform(final Session session, final String entityName, final AuditEntitiesConfiguration audEntitiesCfg, final Serializable id, final Object data, final Object revision) {
    final String auditedEntityName = audEntitiesCfg.getAuditEntityName(entityName);
    final String revisionInfoEntityName = audEntitiesCfg.getRevisionInfoEntityName();
    // Save the audit data
    session.save(auditedEntityName, data);
    // Update the end date of the previous row.
    // 
    // When application reuses identifiers of previously removed entities:
    // The UPDATE statement will no-op if an entity with a given identifier has been
    // inserted for the first time. But in case a deleted primary key value was
    // reused, this guarantees correct strategy behavior: exactly one row with
    // null end date exists for each identifier.
    final boolean reuseEntityIdentifier = audEntitiesCfg.getEnversService().getGlobalConfiguration().isAllowIdentifierReuse();
    if (reuseEntityIdentifier || getRevisionType(audEntitiesCfg, data) != RevisionType.ADD) {
        // Register transaction completion process to guarantee execution of UPDATE statement after INSERT.
        ((EventSource) session).getActionQueue().registerProcess(new BeforeTransactionCompletionProcess() {

            @Override
            public void doBeforeTransactionCompletion(final SessionImplementor sessionImplementor) {
                final Queryable productionEntityQueryable = getQueryable(entityName, sessionImplementor);
                final Queryable rootProductionEntityQueryable = getQueryable(productionEntityQueryable.getRootEntityName(), sessionImplementor);
                final Queryable auditedEntityQueryable = getQueryable(auditedEntityName, sessionImplementor);
                final Queryable rootAuditedEntityQueryable = getQueryable(auditedEntityQueryable.getRootEntityName(), sessionImplementor);
                final String updateTableName;
                if (UnionSubclassEntityPersister.class.isInstance(rootProductionEntityQueryable)) {
                    // this is the condition causing all the problems in terms of the generated SQL UPDATE
                    // the problem being that we currently try to update the in-line view made up of the union query
                    // 
                    // this is extremely hacky means to get the root table name for the union subclass style entities.
                    // hacky because it relies on internal behavior of UnionSubclassEntityPersister
                    // !!!!!! NOTICE - using subclass persister, not root !!!!!!
                    updateTableName = auditedEntityQueryable.getSubclassTableName(0);
                } else {
                    updateTableName = rootAuditedEntityQueryable.getTableName();
                }
                final Type revisionInfoIdType = sessionImplementor.getFactory().getMetamodel().entityPersister(revisionInfoEntityName).getIdentifierType();
                final String revEndColumnName = rootAuditedEntityQueryable.toColumns(audEntitiesCfg.getRevisionEndFieldName())[0];
                final boolean isRevisionEndTimestampEnabled = audEntitiesCfg.isRevisionEndTimestampEnabled();
                // update audit_ent set REVEND = ? [, REVEND_TSTMP = ?] where (prod_ent_id) = ? and REV <> ? and REVEND is null
                final Update update = new Update(sessionImplementor.getFactory().getJdbcServices().getDialect()).setTableName(updateTableName);
                // set REVEND = ?
                update.addColumn(revEndColumnName);
                // set [, REVEND_TSTMP = ?]
                if (isRevisionEndTimestampEnabled) {
                    update.addColumn(rootAuditedEntityQueryable.toColumns(audEntitiesCfg.getRevisionEndTimestampFieldName())[0]);
                }
                // where (prod_ent_id) = ?
                update.addPrimaryKeyColumns(rootProductionEntityQueryable.getIdentifierColumnNames());
                // where REV <> ?
                update.addWhereColumn(rootAuditedEntityQueryable.toColumns(audEntitiesCfg.getRevisionNumberPath())[0], "<> ?");
                // where REVEND is null
                update.addWhereColumn(revEndColumnName, " is null");
                // Now lets execute the sql...
                final String updateSql = update.toStatementString();
                int rowCount = sessionImplementor.doReturningWork(new ReturningWork<Integer>() {

                    @Override
                    public Integer execute(Connection connection) throws SQLException {
                        PreparedStatement preparedStatement = sessionImplementor.getJdbcCoordinator().getStatementPreparer().prepareStatement(updateSql);
                        try {
                            int index = 1;
                            // set REVEND = ?
                            final Number revisionNumber = audEntitiesCfg.getEnversService().getRevisionInfoNumberReader().getRevisionNumber(revision);
                            revisionInfoIdType.nullSafeSet(preparedStatement, revisionNumber, index, sessionImplementor);
                            index += revisionInfoIdType.getColumnSpan(sessionImplementor.getFactory());
                            // set [, REVEND_TSTMP = ?]
                            if (isRevisionEndTimestampEnabled) {
                                final Object revEndTimestampObj = revisionTimestampGetter.get(revision);
                                final Date revisionEndTimestamp = convertRevEndTimestampToDate(revEndTimestampObj);
                                final Type revEndTsType = rootAuditedEntityQueryable.getPropertyType(audEntitiesCfg.getRevisionEndTimestampFieldName());
                                revEndTsType.nullSafeSet(preparedStatement, revisionEndTimestamp, index, sessionImplementor);
                                index += revEndTsType.getColumnSpan(sessionImplementor.getFactory());
                            }
                            // where (prod_ent_id) = ?
                            final Type idType = rootProductionEntityQueryable.getIdentifierType();
                            idType.nullSafeSet(preparedStatement, id, index, sessionImplementor);
                            index += idType.getColumnSpan(sessionImplementor.getFactory());
                            // where REV <> ?
                            final Type revType = rootAuditedEntityQueryable.getPropertyType(audEntitiesCfg.getRevisionNumberPath());
                            revType.nullSafeSet(preparedStatement, revisionNumber, index, sessionImplementor);
                            return sessionImplementor.getJdbcCoordinator().getResultSetReturn().executeUpdate(preparedStatement);
                        } finally {
                            sessionImplementor.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release(preparedStatement);
                            sessionImplementor.getJdbcCoordinator().afterStatementExecution();
                        }
                    }
                });
                if (rowCount != 1 && (!reuseEntityIdentifier || (getRevisionType(audEntitiesCfg, data) != RevisionType.ADD))) {
                    throw new RuntimeException("Cannot update previous revision for entity " + auditedEntityName + " and id " + id);
                }
            }
        });
    }
    sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
}
Also used : BeforeTransactionCompletionProcess(org.hibernate.action.spi.BeforeTransactionCompletionProcess) Queryable(org.hibernate.persister.entity.Queryable) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) Update(org.hibernate.sql.Update) Date(java.util.Date) ReturningWork(org.hibernate.jdbc.ReturningWork) CollectionType(org.hibernate.type.CollectionType) ComponentType(org.hibernate.type.ComponentType) MaterializedNClobType(org.hibernate.type.MaterializedNClobType) MaterializedClobType(org.hibernate.type.MaterializedClobType) MapType(org.hibernate.type.MapType) RevisionType(org.hibernate.envers.RevisionType) Type(org.hibernate.type.Type) SessionImplementor(org.hibernate.engine.spi.SessionImplementor) UnionSubclassEntityPersister(org.hibernate.persister.entity.UnionSubclassEntityPersister)

Example 89 with SessionImplementor

use of org.hibernate.engine.spi.SessionImplementor in project hibernate-orm by hibernate.

the class DefaultFlushEntityEventListener method handleInterception.

protected boolean handleInterception(FlushEntityEvent event) {
    SessionImplementor session = event.getSession();
    EntityEntry entry = event.getEntityEntry();
    EntityPersister persister = entry.getPersister();
    Object entity = event.getEntity();
    // give the Interceptor a chance to modify property values
    final Object[] values = event.getPropertyValues();
    final boolean intercepted = invokeInterceptor(session, entity, entry, values, persister);
    // now we might need to recalculate the dirtyProperties array
    if (intercepted && event.isDirtyCheckPossible() && !event.isDirtyCheckHandledByInterceptor()) {
        int[] dirtyProperties;
        if (event.hasDatabaseSnapshot()) {
            dirtyProperties = persister.findModified(event.getDatabaseSnapshot(), values, entity, session);
        } else {
            dirtyProperties = persister.findDirty(values, entry.getLoadedState(), entity, session);
        }
        event.setDirtyProperties(dirtyProperties);
    }
    return intercepted;
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) EntityEntry(org.hibernate.engine.spi.EntityEntry) SessionImplementor(org.hibernate.engine.spi.SessionImplementor)

Example 90 with SessionImplementor

use of org.hibernate.engine.spi.SessionImplementor in project hibernate-orm by hibernate.

the class DefaultPersistEventListener method onPersist.

/**
 * Handle the given create event.
 *
 * @param event The create event to be handled.
 */
public void onPersist(PersistEvent event, Map createCache) throws HibernateException {
    final SessionImplementor source = event.getSession();
    final Object object = event.getObject();
    final Object entity;
    if (object instanceof HibernateProxy) {
        LazyInitializer li = ((HibernateProxy) object).getHibernateLazyInitializer();
        if (li.isUninitialized()) {
            if (li.getSession() == source) {
                // NOTE EARLY EXIT!
                return;
            } else {
                throw new PersistentObjectException("uninitialized proxy passed to persist()");
            }
        }
        entity = li.getImplementation();
    } else {
        entity = object;
    }
    final String entityName;
    if (event.getEntityName() != null) {
        entityName = event.getEntityName();
    } else {
        entityName = source.bestGuessEntityName(entity);
        event.setEntityName(entityName);
    }
    final EntityEntry entityEntry = source.getPersistenceContext().getEntry(entity);
    EntityState entityState = getEntityState(entity, entityName, entityEntry, source);
    if (entityState == EntityState.DETACHED) {
        // JPA 2, in its version of a "foreign generated", allows the id attribute value
        // to be manually set by the user, even though this manual value is irrelevant.
        // The issue is that this causes problems with the Hibernate unsaved-value strategy
        // which comes into play here in determining detached/transient state.
        // 
        // Detect if we have this situation and if so null out the id value and calculate the
        // entity state again.
        // NOTE: entityEntry must be null to get here, so we cannot use any of its values
        EntityPersister persister = source.getFactory().getEntityPersister(entityName);
        if (ForeignGenerator.class.isInstance(persister.getIdentifierGenerator())) {
            if (LOG.isDebugEnabled() && persister.getIdentifier(entity, source) != null) {
                LOG.debug("Resetting entity id attribute to null for foreign generator");
            }
            persister.setIdentifier(entity, null, source);
            entityState = getEntityState(entity, entityName, entityEntry, source);
        }
    }
    switch(entityState) {
        case DETACHED:
            {
                throw new PersistentObjectException("detached entity passed to persist: " + getLoggableName(event.getEntityName(), entity));
            }
        case PERSISTENT:
            {
                entityIsPersistent(event, createCache);
                break;
            }
        case TRANSIENT:
            {
                entityIsTransient(event, createCache);
                break;
            }
        case DELETED:
            {
                entityEntry.setStatus(Status.MANAGED);
                entityEntry.setDeletedState(null);
                event.getSession().getActionQueue().unScheduleDeletion(entityEntry, event.getObject());
                entityIsDeleted(event, createCache);
                break;
            }
        default:
            {
                throw new ObjectDeletedException("deleted entity passed to persist", null, getLoggableName(event.getEntityName(), entity));
            }
    }
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) LazyInitializer(org.hibernate.proxy.LazyInitializer) EntityEntry(org.hibernate.engine.spi.EntityEntry) SessionImplementor(org.hibernate.engine.spi.SessionImplementor) ObjectDeletedException(org.hibernate.ObjectDeletedException) PersistentObjectException(org.hibernate.PersistentObjectException) HibernateProxy(org.hibernate.proxy.HibernateProxy)

Aggregations

SessionImplementor (org.hibernate.engine.spi.SessionImplementor)97 Test (org.junit.Test)60 Session (org.hibernate.Session)58 Connection (java.sql.Connection)20 TestForIssue (org.hibernate.testing.TestForIssue)18 PreparedStatement (java.sql.PreparedStatement)17 EntityPersister (org.hibernate.persister.entity.EntityPersister)14 Work (org.hibernate.jdbc.Work)13 Statement (java.sql.Statement)12 List (java.util.List)12 Transaction (org.hibernate.Transaction)12 ResultSet (java.sql.ResultSet)11 SQLException (java.sql.SQLException)11 Serializable (java.io.Serializable)8 ArrayList (java.util.ArrayList)7 EntityEntry (org.hibernate.engine.spi.EntityEntry)7 JDBCException (org.hibernate.JDBCException)6 CollectionEntry (org.hibernate.engine.spi.CollectionEntry)6 QueryParameters (org.hibernate.engine.spi.QueryParameters)6 ResultSetProcessor (org.hibernate.loader.plan.exec.process.spi.ResultSetProcessor)6