title: Transaction support for Discriminator model in Muiti-tenancy with Spring + Hibernate
body: <p>Our current development based on Discriminator model in Multi-tenancy. Following is the technical stack we are currently engage with,</p>
  
  <ul>
  <li>Spring 3.1.1.RELEASE </li>
  <li>Hibernate 4.1.6.Final</li>
  </ul>
  
  <p>We are maintain tenant id by keep one column separately in each table. Tenant id filter when session is created. </p>
  
  <p>Example model class.</p>
  
  <pre><code>@Entity
  @FilterDef(name = "tenantFilter", parameters = @ParamDef(name = "tenantIdParam", type = "string"))
  @Filters(@Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
  @Table(name = "assessment")
  public class Assessment implements java.io.Serializable, Comparable&lt;Assessment&gt; {
  
      private static final long serialVersionUID = -2231966582754667029L;
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "id", unique = true, nullable = false)
      private Long id;
      @Column(name = "tenant_id", nullable = false, updatable = false)
      private String tenantId;
  
          // rest of the code...
  }
  </code></pre>
  
  <p>This is the configuration of session factory</p>
  
  <pre><code>&lt;!-- create database connection pool --&gt;
      &lt;bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"&gt;
          &lt;property name="driverClass" value="${jdbc.driverClassName}" /&gt;
          &lt;property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&amp;amp;autoReconnect=true&amp;amp;useUnicode=true&amp;amp;connectionCollation=utf8_general_ci&amp;amp;characterEncoding=UTF-8" /&gt;
          &lt;property name="username" value="${jdbc.username}" /&gt;
          &lt;property name="password" value="${jdbc.password}" /&gt;
          &lt;property name="idleConnectionTestPeriodInMinutes" value="60"/&gt;
          &lt;property name="idleMaxAgeInMinutes" value="240"/&gt;
          &lt;property name="maxConnectionsPerPartition" value="30"/&gt;
          &lt;property name="minConnectionsPerPartition" value="10"/&gt;
          &lt;property name="partitionCount" value="3"/&gt;
          &lt;property name="acquireIncrement" value="5"/&gt;
          &lt;property name="statementsCacheSize" value="100"/&gt;
          &lt;property name="releaseHelperThreads" value="3"/&gt;
      &lt;/bean&gt;
  
      &lt;!-- Hibernate SessionFactory --&gt;
      &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"&gt;
          &lt;property name="dataSource" ref="dataSource"/&gt;
          &lt;property name="packagesToScan" value="lk.gov.elg.orm.model"/&gt;
          &lt;property name="hibernateProperties"&gt;
              &lt;value&gt;
                  hibernate.dialect=${hibernate.dialect}
                  hibernate.hbm2ddl.auto=update
              &lt;/value&gt;
          &lt;/property&gt;
      &lt;/bean&gt;
  
      &lt;bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl"&gt;
          &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
      &lt;/bean&gt;
  
      &lt;bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager"&gt;
          &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
      &lt;/bean&gt;
  </code></pre>
  
  <p>Tenant base session factory </p>
  
  <pre><code>public class TenantBasedSessionFactoryImpl implements TenantBasedSessionFactory {
  
      private SessionFactory sessionFactory;
  
      @Override
      public Session getTenantBasedSession(Object tenantId) {
          Session session = sessionFactory.openSession();
          session.enableFilter("tenantFilter").setParameter("tenantIdParam", tenantId);
          return session;
      }
  
      public void setSessionFactory(SessionFactory sessionFactory) {
          this.sessionFactory = sessionFactory;
      }
  
      public Session getAllTenantBasedSession() {
          Session session = sessionFactory.openSession();
          return session;
      }
  }
  </code></pre>
  
  <p>sample Service class</p>
  
  <pre><code>@Service("assessmentService")
  public class AssessmentServiceImpl implements AssessmentService {
  
      @Autowired
      private AssessmentDao assessmentDao;
  
      public Long saveAssessment(Assessment assessment, Object tenantId) {
          return assessmentDao.saveAssessment(assessment, tenantId);
      }
  }
  </code></pre>
  
  <p>Sample DAO class</p>
  
  <pre><code>@Repository("assessmentDao")
  public class AssessmentDaoImpl implements AssessmentDao {
  
  @Autowired
  private TenantBasedSessionFactory tenantBasedSessionFactory;
  
  public Long saveAssessment(Assessment assessment, Object tenantId) {
          Session session = tenantBasedSessionFactory.getTenantBasedSession(tenantId);
          try {
              session.beginTransaction();
              session.save(assessment);
              session.getTransaction().commit();
              return assessment.getId();
          } catch (HibernateException e) {
              logger.error("Error in persist assessment:", e);
              session.getTransaction().rollback();
              return null;
          } finally {
              session.close();
          }
      }
  }
  </code></pre>
  
  <p>I would like to know is there a way to get the spring transaction support with this Discriminator model for database transactions ?
  And the other thing is I would like to know is there any advantage of give transaction handling to spring rather than handling it by our side?</p>
  
  <p>Thanks in advance.</p>