使用Spring + Hibernate对Muiti-tenancy中的Discriminator模型进行事务支持

时间:2013-05-29 08:21:25

标签: spring hibernate multi-tenant

我们目前在多租户中基于Discriminator模型的开发。以下是我们目前正在参与的技术堆栈,

  • Spring 3.1.1.RELEASE
  • Hibernate 4.1.6.Final

我们通过在每个表中分别保留一列来维护租户ID。创建会话时的租户ID过滤器。

示例模型类。

@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<Assessment> {

    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...
}

这是会话工厂的配置

<!-- create database connection pool -->
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&amp;autoReconnect=true&amp;useUnicode=true&amp;connectionCollation=utf8_general_ci&amp;characterEncoding=UTF-8" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="idleConnectionTestPeriodInMinutes" value="60"/>
        <property name="idleMaxAgeInMinutes" value="240"/>
        <property name="maxConnectionsPerPartition" value="30"/>
        <property name="minConnectionsPerPartition" value="10"/>
        <property name="partitionCount" value="3"/>
        <property name="acquireIncrement" value="5"/>
        <property name="statementsCacheSize" value="100"/>
        <property name="releaseHelperThreads" value="3"/>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="lk.gov.elg.orm.model"/>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=${hibernate.dialect}
                hibernate.hbm2ddl.auto=update
            </value>
        </property>
    </bean>

    <bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="transactionManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

租户基础会议工厂

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;
    }
}

示例服务类

@Service("assessmentService")
public class AssessmentServiceImpl implements AssessmentService {

    @Autowired
    private AssessmentDao assessmentDao;

    public Long saveAssessment(Assessment assessment, Object tenantId) {
        return assessmentDao.saveAssessment(assessment, tenantId);
    }
}

示例DAO类

@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();
        }
    }
}

我想知道有没有办法通过此Discriminator模型获取Spring事务支持数据库事务? 另一件事是我想知道是否有任何优势让交易处理到春天而不是我们这边处理它?<​​/ p>

提前致谢。

1 个答案:

答案 0 :(得分:1)

我有类似的问题,我已经使用方面而不是自定义sessionfactory解决了它,所以我可以利用注释驱动的事务支持

以下代码适用于注释@Tennant

的方面
@Aspect
public class TennantAspect {

    @Autowired
    private SessionFactory sessionFactory;


    @Around("@annotation(Tennant)")
    public Object enableClientFilter(ProceedingJoinPoint pjp) throws Throwable {
        Object obj;
        boolean isDAO=(pjp.getTarget() instanceof BaseDAO<?,?>);
        try {
            if(isDAO){
                Authentication auth=SecurityContextHolder.getContext().getAuthentication();
                if(auth!=null){
                    User user=(User) auth.getPrincipal();
                    this.sessionFactory.getCurrentSession().enableFilter("clientFilter").setParameter("clientId", user.getClientId());
                }
            }
            obj=pjp.proceed();
        }finally {
            if(isDAO)
                this.sessionFactory.getCurrentSession().disableFilter("clientFilter");
        }
        return obj;
    }
}

希望这能解决你的问题。

或者你也可以看看hiberante&amp; amp;春天

http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html https://github.com/mariofts/spring-multitenancy