3

我们目前的开发基于多租户中的鉴别器模型。以下是我们目前正在使用的技术堆栈,

  • Spring 3.1.1.RELEASE
  • 休眠 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();
        }
    }
}

我想知道有没有办法通过这个数据库事务的鉴别器模型获得 spring 事务支持?另一件事是我想知道将事务处理交给spring而不是在我们身边处理有什么好处吗?

提前致谢。

4

1 回答 1

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 和 spring 提供的租赁支持

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

于 2013-05-29T09:04:29.033 回答