HHH-11732 - HHH000352: in StatelessSession on rollback with JDBC batch
This commit is contained in:
parent
becc1d7473
commit
1392b43852
|
@ -38,8 +38,10 @@ import org.hibernate.internal.CoreLogging;
|
|||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jdbc.WorkExecutor;
|
||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||
import org.hibernate.resource.jdbc.ResourceRegistry;
|
||||
import org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl;
|
||||
import org.hibernate.resource.jdbc.internal.LogicalConnectionProvidedImpl;
|
||||
import org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransaction;
|
||||
|
@ -94,13 +96,17 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
JdbcSessionOwner owner) {
|
||||
this.isUserSuppliedConnection = userSuppliedConnection != null;
|
||||
|
||||
final ResourceRegistry resourceRegistry = new ResourceRegistryStandardImpl(
|
||||
owner.getJdbcSessionContext().getObserver()
|
||||
);
|
||||
if ( isUserSuppliedConnection ) {
|
||||
this.logicalConnection = new LogicalConnectionProvidedImpl( userSuppliedConnection );
|
||||
this.logicalConnection = new LogicalConnectionProvidedImpl( userSuppliedConnection, resourceRegistry );
|
||||
}
|
||||
else {
|
||||
this.logicalConnection = new LogicalConnectionManagedImpl(
|
||||
owner.getJdbcConnectionAccess(),
|
||||
owner.getJdbcSessionContext()
|
||||
owner.getJdbcSessionContext(),
|
||||
resourceRegistry
|
||||
);
|
||||
}
|
||||
this.owner = owner;
|
||||
|
|
|
@ -83,4 +83,14 @@ public class JdbcObserverImpl implements JdbcObserver {
|
|||
public void jdbcExecuteBatchEnd() {
|
||||
session.getEventListenerManager().jdbcExecuteBatchEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jdbcReleaseRegistryResourcesStart() {
|
||||
session.getJdbcCoordinator().abortBatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jdbcReleaseRegistryResourcesEnd() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,9 +15,6 @@ import java.sql.SQLException;
|
|||
import org.hibernate.ConnectionAcquisitionMode;
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.ResourceClosedException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
|
@ -48,12 +45,6 @@ public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImple
|
|||
|
||||
private boolean providerDisablesAutoCommit;
|
||||
|
||||
public LogicalConnectionManagedImpl(
|
||||
JdbcConnectionAccess jdbcConnectionAccess,
|
||||
JdbcSessionContext jdbcSessionContext) {
|
||||
this( jdbcConnectionAccess, jdbcSessionContext, new ResourceRegistryStandardImpl() );
|
||||
}
|
||||
|
||||
public LogicalConnectionManagedImpl(
|
||||
JdbcConnectionAccess jdbcConnectionAccess,
|
||||
JdbcSessionContext jdbcSessionContext,
|
||||
|
|
|
@ -28,10 +28,6 @@ public class LogicalConnectionProvidedImpl extends AbstractLogicalConnectionImpl
|
|||
private final boolean initiallyAutoCommit;
|
||||
private boolean closed;
|
||||
|
||||
public LogicalConnectionProvidedImpl(Connection providedConnection) {
|
||||
this( providedConnection, new ResourceRegistryStandardImpl() );
|
||||
}
|
||||
|
||||
public LogicalConnectionProvidedImpl(Connection providedConnection, ResourceRegistry resourceRegistry) {
|
||||
this.resourceRegistry = resourceRegistry;
|
||||
if ( providedConnection == null ) {
|
||||
|
@ -89,7 +85,7 @@ public class LogicalConnectionProvidedImpl extends AbstractLogicalConnectionImpl
|
|||
public LogicalConnectionImplementor makeShareableCopy() {
|
||||
errorIfClosed();
|
||||
|
||||
return new LogicalConnectionProvidedImpl( providedConnection );
|
||||
return new LogicalConnectionProvidedImpl( providedConnection, new ResourceRegistryStandardImpl() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.JDBCException;
|
|||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.resource.jdbc.ResourceRegistry;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcObserver;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -32,6 +33,8 @@ import org.hibernate.resource.jdbc.ResourceRegistry;
|
|||
public class ResourceRegistryStandardImpl implements ResourceRegistry {
|
||||
private static final CoreMessageLogger log = CoreLogging.messageLogger( ResourceRegistryStandardImpl.class );
|
||||
|
||||
private final JdbcObserver jdbcObserver;
|
||||
|
||||
private final Map<Statement, Set<ResultSet>> xref = new HashMap<Statement, Set<ResultSet>>();
|
||||
private final Set<ResultSet> unassociatedResultSets = new HashSet<ResultSet>();
|
||||
|
||||
|
@ -41,6 +44,14 @@ public class ResourceRegistryStandardImpl implements ResourceRegistry {
|
|||
|
||||
private Statement lastQuery;
|
||||
|
||||
public ResourceRegistryStandardImpl() {
|
||||
this( null );
|
||||
}
|
||||
|
||||
public ResourceRegistryStandardImpl(JdbcObserver jdbcObserver) {
|
||||
this.jdbcObserver = jdbcObserver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegisteredResources() {
|
||||
return hasRegistered( xref )
|
||||
|
@ -285,6 +296,10 @@ public class ResourceRegistryStandardImpl implements ResourceRegistry {
|
|||
public void releaseResources() {
|
||||
log.trace( "Releasing JDBC resources" );
|
||||
|
||||
if ( jdbcObserver != null ) {
|
||||
jdbcObserver.jdbcReleaseRegistryResourcesStart();
|
||||
}
|
||||
|
||||
for ( Map.Entry<Statement, Set<ResultSet>> entry : xref.entrySet() ) {
|
||||
if ( entry.getValue() != null ) {
|
||||
closeAll( entry.getValue() );
|
||||
|
@ -331,6 +346,9 @@ public class ResourceRegistryStandardImpl implements ResourceRegistry {
|
|||
nclobs.clear();
|
||||
}
|
||||
|
||||
if ( jdbcObserver != null ) {
|
||||
jdbcObserver.jdbcReleaseRegistryResourcesEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRegistered(Map resource) {
|
||||
|
|
|
@ -27,4 +27,8 @@ public interface JdbcObserver {
|
|||
public void jdbcExecuteBatchStart();
|
||||
public void jdbcExecuteBatchEnd();
|
||||
|
||||
default public void jdbcReleaseRegistryResourcesStart() {}
|
||||
default public void jdbcReleaseRegistryResourcesEnd() {}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.test.resource.transaction.jdbc;
|
||||
|
||||
import org.hibernate.resource.jdbc.internal.LogicalConnectionProvidedImpl;
|
||||
import org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl;
|
||||
|
||||
import org.hibernate.test.resource.common.DatabaseConnectionInfo;
|
||||
|
||||
|
@ -15,6 +16,6 @@ import org.hibernate.test.resource.common.DatabaseConnectionInfo;
|
|||
*/
|
||||
public class LogicalConnectionTestingImpl extends LogicalConnectionProvidedImpl {
|
||||
public LogicalConnectionTestingImpl() throws Exception {
|
||||
super( DatabaseConnectionInfo.INSTANCE.makeConnection() );
|
||||
super( DatabaseConnectionInfo.INSTANCE.makeConnection(), new ResourceRegistryStandardImpl() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package org.hibernate.test.stateless;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.SessionImpl;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
||||
import org.hibernate.testing.logger.Triggerable;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class StatelessSessionConnectionTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Rule
|
||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule( Logger.getMessageLogger( CoreMessageLogger.class, AbstractBatchImpl.class.getName() ) );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Employee.class
|
||||
};
|
||||
}
|
||||
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( AvailableSettings.STATEMENT_BATCH_SIZE, 10 );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-11732" )
|
||||
public void test() {
|
||||
Triggerable triggerable = logInspection.watchForLogMessages( "HHH000352" );
|
||||
triggerable.reset();
|
||||
|
||||
StatelessSession session = entityManagerFactory().unwrap( SessionFactory.class ).openStatelessSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
try {
|
||||
Employee employee = new Employee( "1", "2", 1 );
|
||||
employee.setId( 1 );
|
||||
session.insert( employee );
|
||||
|
||||
tx.rollback();
|
||||
}
|
||||
catch (HibernateException e) {
|
||||
if ( tx != null ) {
|
||||
tx.rollback();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
assertFalse( triggerable.wasTriggered() );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
private int salary;
|
||||
|
||||
public Employee() {}
|
||||
|
||||
public Employee(String fname, String lname, int salary) {
|
||||
this.firstName = fname;
|
||||
this.lastName = lname;
|
||||
this.salary = salary;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId( Integer id ) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName( String first_name ) {
|
||||
this.firstName = first_name;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName( String last_name ) {
|
||||
this.lastName = last_name;
|
||||
}
|
||||
|
||||
public int getSalary() {
|
||||
return salary;
|
||||
}
|
||||
|
||||
public void setSalary( int salary ) {
|
||||
this.salary = salary;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue