HHH-13861 Expose the doWork() and doReturningWork() APIs on StatelessSession as well

This commit is contained in:
Andrea Boriero 2020-02-12 10:15:05 +00:00 committed by Sanne Grinovero
parent 6b1ef47a2d
commit 2f2d30e4e5
5 changed files with 201 additions and 54 deletions

View File

@ -18,8 +18,6 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate; import javax.persistence.criteria.CriteriaUpdate;
import org.hibernate.graph.RootGraph; import org.hibernate.graph.RootGraph;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jpa.HibernateEntityManager; import org.hibernate.jpa.HibernateEntityManager;
import org.hibernate.query.NativeQuery; import org.hibernate.query.NativeQuery;
import org.hibernate.stat.SessionStatistics; import org.hibernate.stat.SessionStatistics;
@ -960,27 +958,6 @@ public interface Session extends SharedSessionContract, EntityManager, Hibernate
*/ */
void setReadOnly(Object entityOrProxy, boolean readOnly); void setReadOnly(Object entityOrProxy, boolean readOnly);
/**
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session.
*
* @param work The work to be performed.
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
*/
void doWork(Work work) throws HibernateException;
/**
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session. After
* execution returns the result of the {@link ReturningWork#execute} call.
*
* @param work The work to be performed.
* @param <T> The type of the result returned from the work
*
* @return the result from calling {@link ReturningWork#execute}.
*
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
*/
<T> T doReturningWork(ReturningWork<T> work) throws HibernateException;
@Override @Override
<T> RootGraph<T> createEntityGraph(Class<T> rootType); <T> RootGraph<T> createEntityGraph(Class<T> rootType);

View File

@ -8,6 +8,8 @@ package org.hibernate;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.procedure.ProcedureCall; import org.hibernate.procedure.ProcedureCall;
import org.hibernate.query.QueryProducer; import org.hibernate.query.QueryProducer;
@ -190,4 +192,30 @@ public interface SharedSessionContract extends QueryProducer, Serializable {
* @see org.hibernate.boot.SessionFactoryBuilder#applyJdbcBatchSize * @see org.hibernate.boot.SessionFactoryBuilder#applyJdbcBatchSize
*/ */
void setJdbcBatchSize(Integer jdbcBatchSize); void setJdbcBatchSize(Integer jdbcBatchSize);
/**
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session.
*
* @param work The work to be performed.
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
*/
default void doWork(Work work) throws HibernateException {
throw new UnsupportedOperationException( "The doWork method has not been implemented in this implementation of org.hibernate.engine.spi.SharedSessionContractImplemento" );
}
/**
* Controller for allowing users to perform JDBC related work using the Connection managed by this Session. After
* execution returns the result of the {@link ReturningWork#execute} call.
*
* @param work The work to be performed.
* @param <T> The type of the result returned from the work
*
* @return the result from calling {@link ReturningWork#execute}.
*
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
*/
default <T> T doReturningWork(ReturningWork<T> work) throws HibernateException {
throw new UnsupportedOperationException( "The doReturningWork method has not been implemented in this implementation of org.hibernate.engine.spi.SharedSessionContractImplemento" );
}
} }

View File

@ -62,6 +62,9 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.transaction.internal.TransactionImpl; import org.hibernate.engine.transaction.internal.TransactionImpl;
import org.hibernate.engine.transaction.spi.TransactionImplementor; import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy; import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer; import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
@ -1059,6 +1062,28 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
return getNativeQueryImplementor( queryString, true ); return getNativeQueryImplementor( queryString, true );
} }
@Override
public void doWork(final Work work) throws HibernateException {
WorkExecutorVisitable<Void> realWork = (workExecutor, connection) -> {
workExecutor.executeWork( work, connection );
return null;
};
doWork( realWork );
}
@Override
public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException {
WorkExecutorVisitable<T> realWork = (workExecutor, connection) -> workExecutor.executeReturningWork(
work,
connection
);
return doWork( realWork );
}
private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException {
return getJdbcCoordinator().coordinateWork( work );
}
protected NativeQueryImplementor getNativeQueryImplementor( protected NativeQueryImplementor getNativeQueryImplementor(
String queryString, String queryString,
boolean isOrdinalParameterZeroBased) { boolean isOrdinalParameterZeroBased) {

View File

@ -135,10 +135,6 @@ import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.hql.spi.QueryTranslator; import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.internal.CriteriaImpl.CriterionEntry; import org.hibernate.internal.CriteriaImpl.CriterionEntry;
import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.CacheModeHelper;
@ -2296,33 +2292,6 @@ public class SessionImpl
persistenceContext.setReadOnly( entity, readOnly ); persistenceContext.setReadOnly( entity, readOnly );
} }
@Override
public void doWork(final Work work) throws HibernateException {
WorkExecutorVisitable<Void> realWork = new WorkExecutorVisitable<Void>() {
@Override
public Void accept(WorkExecutor<Void> workExecutor, Connection connection) throws SQLException {
workExecutor.executeWork( work, connection );
return null;
}
};
doWork( realWork );
}
@Override
public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException {
WorkExecutorVisitable<T> realWork = new WorkExecutorVisitable<T>() {
@Override
public T accept(WorkExecutor<T> workExecutor, Connection connection) throws SQLException {
return workExecutor.executeReturningWork( work, connection );
}
};
return doWork( realWork );
}
private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException {
return getJdbcCoordinator().coordinateWork( work );
}
@Override @Override
public void afterScrollOperation() { public void afterScrollOperation() {
// nothing to do in a stateful session // nothing to do in a stateful session

View File

@ -0,0 +1,148 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.stateless;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.StatelessSession;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Andrea Boriero
*/
@RequiresDialect(H2Dialect.class)
public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
public static final String EXPECTED_ENTITY_NAME = "test";
public static final Integer PERSISTED_TEST_ENTITY_ID = 1;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { TestEntity.class };
}
@Before
public void setUp() {
inTransaction(
session -> {
TestEntity entity = new TestEntity( PERSISTED_TEST_ENTITY_ID, EXPECTED_ENTITY_NAME );
session.save( entity );
}
);
}
@After
public void tearDown() {
inTransaction(
session -> {
session.createQuery( "delete from TestEntity" ).executeUpdate();
}
);
}
@Test
public void testDoReturningWork() {
String retrievedEntityName;
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
retrievedEntityName = statelessSession.doReturningWork(
(connection) -> {
try (PreparedStatement preparedStatement = connection.prepareStatement(
"SELECT NAME FROM TEST_ENTITY WHERE ID = ?" )) {
preparedStatement.setInt( 1, PERSISTED_TEST_ENTITY_ID );
ResultSet resultSet = preparedStatement.executeQuery();
String name = null;
if ( resultSet.next() ) {
name = resultSet.getString( 1 );
}
return name;
}
}
);
}
assertThat( retrievedEntityName, is( EXPECTED_ENTITY_NAME ) );
}
@Test
public void testDoWork() {
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
statelessSession.doWork(
(connection) -> {
try (PreparedStatement preparedStatement = connection.prepareStatement(
"DELETE FROM TEST_ENTITY " )) {
preparedStatement.execute();
}
}
);
}
assertThatAllTestEntitiesHaveBeenDeleted();
}
private void assertThatAllTestEntitiesHaveBeenDeleted() {
inTransaction( session -> {
List results = session.createQuery( "from TestEntity" ).list();
assertThat( results.size(), is( 0 ) );
} );
}
@Entity(name = "TestEntity")
@Table(name = "TEST_ENTITY")
public static class TestEntity {
@Id
@Column(name = "ID")
private Integer id;
@Column(name = "NAME")
private String name;
public TestEntity() {
}
public TestEntity(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}