【问题标题】:Transaction support for Discriminator model in Muiti-tenancy with Spring + Hibernate使用 Spring + Hibernate 在多租户中对鉴别器模型的事务支持
【发布时间】:2013-05-24 09:56:40
【问题描述】:

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

  • 春季 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而不是在我们身边处理有什么好处?

提前致谢。

【问题讨论】:

    标签: spring hibernate multi-tenant


    【解决方案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

    【讨论】:

    • 似乎是一个好方法,但有点危险。将来意外删除 DAO 方法上的注释将导致不必要的数据泄露。租户将查看其他租户数据
    猜你喜欢
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 2019-06-15
    • 2019-06-23
    • 2014-02-07
    相关资源
    最近更新 更多