当前位置: 代码迷 >> Eclipse >> 跟小弟我上“云”端(四)使用eclipselink构建企业级多租户应用
  详细解决方案

跟小弟我上“云”端(四)使用eclipselink构建企业级多租户应用

热度:147   发布时间:2016-04-22 23:46:19.0
跟我上“云”端(四)使用eclipselink构建企业级多租户应用

上一篇博客中我们介绍了多租户的数据隔离,文中具体的介绍了hibernate和eclipselink对于多租户的实现情况,博客的最后,我也对hibernate实现多租户的细节上做了解释,这次,我想带大家一起来使用eclipselink构建企业级的多租户项目。

eclipselink的三种实现

由于eclipselink完整实现了jpa规范,我们就可以使用ejb构建一个企业级的多租户项目,首先eclipselink支持3中多租户的模式:
- Single-Table Multi-tenancy,依靠租户区分列(tenant discriminator columns)来隔离表的行,实现多租户共享表。
- Table-Per-Tenant Multi-tenancy,依靠表的租户区分(table tenant discriminator)来隔离表,实现一租户一个表,大体类似于上文的共享数据库独立Schema模式。
- Virtual Private Database(VPD ) Multi-tenancy,依靠 Oracle VPD 自身的安全访问策略(基于动态SQL where子句特性),实现多租户共享表。

Table-Per-Tenant Multi-tenancy实现

  • 我想将的是第二种方式,因为它在性能、分离度以及灵活性上都是比较合适的。
  • 首先是persistence.xml的内容,经过上一篇博客的介绍,我们应该已经配置好eclipselink的基本使用环境。

Persistence.xml配置:

<?xml version="1.0" encoding="UTF-8"?><persistence version="2.0"    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">    <!-- 给定persistence-unit名字-->    <persistence-unit name="MT_HOTEL_SERVICE"        transaction-type="JTA">        <!-- 使用eclipselink的持久化实现-->        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>        <!-- 使用jboss中配置的数据源-->        <jta-data-source>java:jboss/datasources/JcMysqlDS</jta-data-source>        <!-- 由于配置了实体自动扫描此处不用列出系统中的试题-->        <properties>            <!-- 修改第一次加载时间长的问题 -->            <property name="eclipselink.deploy-on-startup" value="True" />            <!-- 运行执行本地sql查询 -->            <property name="eclipselink.jdbc.allow-native-sql-queries"                value="true" />            <!-- 设置服务器类型 -->            <property name="eclipselink.target-server" value="JBoss" />            <!-- logging 级别配置-->            <property name="eclipselink.logging.level" value="FINE" />            <!-- 配置静态织入-->            <property name="eclipselink.weaving" value="static" />            <!-- 设置自定义主键生成策略-->            <property name="eclipselink.session.customizer" value="com.tgb.itoo.base.util.uuid.UUIDSequence" />        </properties>    </persistence-unit></persistence>
  • 配置中每一行的配置都有做出解释,这里就不再多说了。

BaseEntity配置

  • 对于实体的配置:首先是使用的实体继承,BaseEntity的代码如下:
package com.tgb.itoo.base.entity;import java.util.Date;import javax.persistence.Column;import javax.persistence.EntityListeners;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.MappedSuperclass;import javax.persistence.Temporal;import javax.persistence.TemporalType;import javax.persistence.Transient;@MappedSuperclass@EntityListeners(value = { EntityListener.class })public abstract class BaseEntity implements IdEntity {    private static final long serialVersionUID = 1L;    public BaseEntity() {        super();    }    @Id    @GeneratedValue(generator = "system-uuid")//自定义uuid生成策略    @Column(name = "id")    protected String id;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    /**     * 数据库名称     */    @Transient //不进行持久化    private String dataBaseName;    public String getDataBaseName() {        return dataBaseName;    }    public void setDataBaseName(String dataBaseName) {        this.dataBaseName = dataBaseName;    }    /**     * 备注     */    @Column(name = "comment", length = 255)    private String comment;    /**     * 操作人     */    @Column(name = "operator", length = 20)    private String operator;    ……}
  • BaseEntity中定义了实体的公共属性,其中重点关注两个属性值
    1. id:id使用的是自定义的uuid生成策略,这个在下一篇博客中介绍。
    2. dataBasename:从名字上来说很明了就是数据库名,但是这个属性不是用来持久化的,所以使用@Transient注解,这个属性主要是为了传递参数的,会在实现多租户的时候用到,因为对于任何实体的每一次操作都应该确定是那个承租者的操作,就要使数据的CRUD都要对应自己的数据库。

具体某个实体的设计

package com.tgb.itoo.authority.entity;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Table;import org.eclipse.persistence.annotations.Multitenant;import org.eclipse.persistence.annotations.MultitenantType;import org.eclipse.persistence.annotations.TenantTableDiscriminator;import org.eclipse.persistence.annotations.TenantTableDiscriminatorType;import com.tgb.itoo.base.entity.TimeBaseEntity;/** * 角色实体 * @author hanyi * */@Entity@Table(name="ta_role")@Multitenant(value=MultitenantType.TABLE_PER_TENANT)@TenantTableDiscriminator(type=TenantTableDiscriminatorType.SCHEMA, contextProperty="tenant_id")public class Role extends TimeBaseEntity {    private static final long serialVersionUID = 598970641717338526L;    /**     * 角色名称     */    @Column(name = "roleName", length = 32)    private String roleName;    /**     * 角色描述     */    @Column(name = "roleDescribe", length = 100)    private String roleDescribe;    ……}
  • 应该注意实体中对于多租户的注解,其中设置了MultitenantType.TABLE_PER_TENANT也就是使用依靠表的租户区分,TenantTableDiscriminatorType有三种类型,这里使用SCHEMA,也就是每个租户使用独立的SCHEMA,定义了contextProperty=”tenant_id”,这也就设置了entitymanager可以根据tenant_id属性区别不同的租户。

entitymanager的注入

    //实体管理器,管理实体持久化操作,通过容器注入    @PersistenceContext(unitName = "MT_HOTEL_SERVICE")    protected EntityManager em;

设置多租户属性

/** * 根据数据库名字,得到当前操作对应的实体管理器的名字 * @return 实体管理器 */protected EntityManager getEntityManager() {            //dataBaseName的值,给实体管理器赋值,此处的tenant_id是在实体注解时规定,只要统一可以是任何值。    if (dataBaseName!=null && !dataBaseName.equals(""))     {        em.setProperty("tenant_id", dataBaseName);    }    //如果dataBaseName的值为空,那么就选择一个默认的库,这里选择的是根库(base)    else     {        em.setProperty("tenant_id", "base);    }    return this.em;}

具体Eao的方法

/**     * @author hanyi     * @MethodName : save     * @Description : 无返回值的泛型保存方法     * @param t:要保存的实体     */    public  void save(Object entity) {        //从实体类型中拿到当前操作的数据库名字        getDataBaseName(entity);        //取得实体管理器,进行持久化操作        getEntityManager().persist(entity);         }
  • 这里忽略了从getDataBaseName(entity)方法的代码,其主要作用是通过反射得到前台设置的databasename的值,之后再getEntityManager的时候使用。

完成配置

到此eclipselink+ejb+jpa实现企业级的多租户应用的数据层隔离也就解决了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

1楼u010028869昨天 22:20
期待ing