Skip to content

Instantly share code, notes, and snippets.

@jelies
Last active December 4, 2024 12:26

Revisions

  1. jelies revised this gist Mar 17, 2013. 1 changed file with 0 additions and 17 deletions.
    17 changes: 0 additions & 17 deletions PersitenceConfig.java
    Original file line number Diff line number Diff line change
    @@ -1,28 +1,11 @@
    package com.jelies.spring3tomcat7.config;

    import java.util.Properties;

    import javax.annotation.PostConstruct;
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.orm.hibernate3.HibernateExceptionTranslator;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.transaction.annotation.TransactionManagementConfigurer;

    import com.jelies.spring3tomcat7.config.util.ConfigUtils;
    import com.jelies.spring3tomcat7.config.util.hibernate.StatelessSessionFactoryBean;

    @Configuration
  2. jelies created this gist Mar 17, 2013.
    35 changes: 35 additions & 0 deletions MyRepositoryImpl.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    package com.jelies.spring3tomcat7.repository;

    import org.hibernate.Criteria;
    import org.hibernate.ScrollableResults;
    import org.hibernate.StatelessSession;
    import org.hibernate.Transaction;
    import org.hibernate.criterion.Order;
    import org.hibernate.criterion.Restrictions;
    import org.joda.time.LocalDate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;

    import com.jelies.spring3tomcat7.model.entity.User;

    public class MyRepositoryImpl implements MyRepositoryCustom {

    @Autowired
    private StatelessSession statelessSession;

    @Override
    @Transactional
    public void myBatchStatements() {
    Criteria c = statelessSession.createCriteria(User.class);

    ScrollableResults itemCursor = c.scroll();

    while (itemCursor.next()) {
    myUpdate((User) itemCursor.get(0));
    }
    itemCursor.close();

    return true;
    }

    }
    41 changes: 41 additions & 0 deletions PersitenceConfig.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    package com.jelies.spring3tomcat7.config;

    import java.util.Properties;

    import javax.annotation.PostConstruct;
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.orm.hibernate3.HibernateExceptionTranslator;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.transaction.annotation.TransactionManagementConfigurer;

    import com.jelies.spring3tomcat7.config.util.ConfigUtils;
    import com.jelies.spring3tomcat7.config.util.hibernate.StatelessSessionFactoryBean;

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories("com.jelies.spring3tomcat7.repository")
    public class PersistenceConfig implements TransactionManagementConfigurer {

    ...

    @Bean
    public StatelessSessionFactoryBean statelessSessionFactory() {
    return new StatelessSessionFactoryBean();
    }

    ...
    }
    163 changes: 163 additions & 0 deletions StatelessSessionFactoryBean.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,163 @@
    package com.jelies.spring3tomcat7.config.spring;

    import static org.springframework.orm.jpa.EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
    import static org.springframework.util.ReflectionUtils.invokeMethod;

    import java.sql.Connection;

    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;

    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.hibernate.SessionFactory;
    import org.hibernate.StatelessSession;
    import org.hibernate.ejb.HibernateEntityManagerFactory;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.engine.transaction.spi.TransactionContext;
    import org.springframework.aop.framework.ProxyFactory;
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.datasource.DataSourceUtils;
    import org.springframework.orm.jpa.EntityManagerFactoryUtils;
    import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;
    import org.springframework.transaction.support.ResourceHolderSynchronization;
    import org.springframework.transaction.support.TransactionSynchronizationAdapter;
    import org.springframework.transaction.support.TransactionSynchronizationManager;

    /**
    * Hibernate's {@link StatelessSession} factory which will be bound to the
    * current transaction. This factory returns a Proxy which delegates method
    * calls to the underlying {@link StatelessSession} bound to transaction. At the
    * end of the transaction the session is automatically closed. This class
    * borrows idea's from {@link DataSourceUtils},
    * {@link EntityManagerFactoryUtils}, {@link ResourceHolderSynchronization} and
    * {@link LocalEntityManagerFactoryBean}.
    */
    public class StatelessSessionFactoryBean implements FactoryBean<StatelessSession> {

    private final HibernateEntityManagerFactory entityManagerFactory;
    private SessionFactory sessionFactory;

    @Autowired
    public StatelessSessionFactoryBean(HibernateEntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory;
    this.sessionFactory = entityManagerFactory.getSessionFactory();
    }

    /**
    * Use this to override the {@link SessionFactory} obtained from the
    * {@link EntityManagerFactory}. Please note that the connection will still
    * be used from the {@link EntityManager}.
    */
    public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
    }

    @Override
    public StatelessSession getObject() throws Exception {
    StatelessSessionInterceptor statelessSessionInterceptor = new StatelessSessionInterceptor(
    entityManagerFactory, sessionFactory);
    return ProxyFactory.getProxy(StatelessSession.class, statelessSessionInterceptor);
    }

    @Override
    public Class<?> getObjectType() {
    return StatelessSession.class;
    }

    @Override
    public boolean isSingleton() {
    return true;
    }

    private static class StatelessSessionInterceptor implements MethodInterceptor {

    private final EntityManagerFactory entityManagerFactory;
    private final SessionFactory sessionFactory;

    public StatelessSessionInterceptor(EntityManagerFactory entityManagerFactory,
    SessionFactory sessionFactory) {
    this.entityManagerFactory = entityManagerFactory;
    this.sessionFactory = sessionFactory;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    StatelessSession statelessSession = getCurrentSession();
    return invokeMethod(invocation.getMethod(), statelessSession, invocation.getArguments());
    }

    private StatelessSession getCurrentSession() {
    if (!TransactionSynchronizationManager.isActualTransactionActive()) {
    throw new IllegalStateException(
    "There should be an active transaction for the current thread.");
    }
    StatelessSession statelessSession = (StatelessSession) TransactionSynchronizationManager
    .getResource(sessionFactory);
    if (statelessSession == null) {
    statelessSession = openNewStatelessSession();
    bindWithTransaction(statelessSession);
    }
    return statelessSession;
    }

    private StatelessSession openNewStatelessSession() {
    Connection connection = obtainPhysicalConnection();
    return sessionFactory.openStatelessSession(connection);
    }

    /**
    * It is important we obtain the physical (real) connection otherwise it
    * will be double proxied and there will be problems releasing the
    * connection.
    */
    private Connection obtainPhysicalConnection() {
    EntityManager entityManager = EntityManagerFactoryUtils
    .getTransactionalEntityManager(entityManagerFactory);
    SessionImplementor sessionImplementor = (SessionImplementor) entityManager
    .getDelegate();
    return sessionImplementor.getTransactionCoordinator().getJdbcCoordinator()
    .getLogicalConnection().getConnection();
    }

    private void bindWithTransaction(StatelessSession statelessSession) {
    TransactionSynchronizationManager
    .registerSynchronization(new StatelessSessionSynchronization(sessionFactory,
    statelessSession));
    TransactionSynchronizationManager.bindResource(sessionFactory, statelessSession);
    }
    }

    private static class StatelessSessionSynchronization extends TransactionSynchronizationAdapter {

    private final SessionFactory sessionFactory;
    private final StatelessSession statelessSession;

    public StatelessSessionSynchronization(SessionFactory sessionFactory,
    StatelessSession statelessSession) {
    this.sessionFactory = sessionFactory;
    this.statelessSession = statelessSession;
    }

    @Override
    public int getOrder() {
    return ENTITY_MANAGER_SYNCHRONIZATION_ORDER - 100;
    }

    @Override
    public void beforeCommit(boolean readOnly) {
    if (!readOnly) {
    ((TransactionContext) statelessSession).managedFlush();
    }
    }

    @Override
    public void beforeCompletion() {
    TransactionSynchronizationManager.unbindResource(sessionFactory);
    statelessSession.close();
    }

    }

    }