您好,我使用Vaadin Framework,JPA Eclipselink AS ORM,MySQL作为数据库开发Web应用程序。目前,我正在努力为我的应用程序实施多承诺结构。在这里,我在共享数据库策略中选择具有不同架构的table_per_tenant,因为我已经有一些租户。
这是我特定特定实体的一个示例:
@Entity
@Multitenant(MultitenantType.TABLE_PER_TENANT)
@TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
public class UserAccount implements Serializable {
......
}
这是我在persistence.xml中租户的持久性单位:
<persistence-unit name="PU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>Includes all tenant table class</class>
<properties>
<property name="eclipselink.cache.shared.default" value="false"/>
<!-- container isn upcloud ??-->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/?rewriteBatchedStatements=true&characterEncoding=UTF-8&connectionCollation=utf8_general_ci&zeroDateTimeBehavior=convertToNull&useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8&characterEncoding=utf8&characterEncoding=UTF-8&characterSetResults=UTF-8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
<property name="eclipselink.jdbc.batch-writing.size" value="1000"/>
<property name="hibernate.connection.useUnicode" value="true"/>
<property name="hibernate.connection.characterEncoding" value="UTF-8"/>
</properties>
</persistence-unit>
现在我得到了这样的EntityManager:
public static EntityManager createTenantSpecificEntityManager(){
EntityManager em = Persistence.createEntityManagerFactory("PU").createEntityManager(getProperties());
return em;
}
private static Map<String, Object> getProperties(){
Map<String, Object> properties = new HashMap<>();
properties.put("javax.persistence.jdbc.url", getDataBaseConnectionURL(COMPANY_NAME_AS_TENENT_ID));
return properties;
}
public static String getDataBaseConnectionURL(String schemaName){
String str = "jdbc:mysql://localhost:3306/?rewriteBatchedStatements=true&characterEncoding=UTF-8&connectionCollation=utf8_general_ci&zeroDateTimeBehavior=convertToNull&useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8&characterEncoding=utf8&characterEncoding=UTF-8&characterSetResults=UTF-8";//for testing purpose
StringBuilder sb = new StringBuilder(str);
sb.insert(sb.indexOf("?"), schemaName);
return sb.toString();
}
现在我正在使用这样的EntityManager:
em = createTenantSpecificEntityManager();
em.getTransaction().begin();
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, COMPANY_NAME_AS_TENENT_ID);
.......
Do any operation here
.......
em.getTransaction().commit();
em.close();
在应用程序中,用户可以登录特定的租户(他可以在其中访问该租户(。因此,一次只能访问一个租户的数据。
我的应用程序使其成为多租户是正确的方法吗?我可以做任何改进吗?
一个人可以使用threadlocal,如下所示:
public class TenantContext {
private static final ThreadLocal<String> TENANT_TL = new ThreadLocal<>();
public static String getTenantId() {
return TENANT_TL.get();
}
public static void setTenantId(String tenantId) {
TENANT_TL.set(tenantId);
}
}
通常在拦截器中,可以将tenantid设置为身份验证。在创建EntityManager时,可以使用上述租户,如下所示:
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, TenantContext.getTenantId());
我使用Eclipse链接和弹簧数据创建了一个关于多租户(每位租户表(的Java示例。现有应用程序可以通过最小的代码更改转换为多租户。这是使用字节码仪器完成的。选择了这个想法来利用弹簧数据的完整功能。
一个人可以执行MultitenantStest以查看其工作。
这个想法是开源的,可在Maven Central