上一篇博客中我们介绍了多租户的数据隔离,文中具体的介绍了hibernate和eclipselink对于多租户的实现情况,博客的最后,我也对hibernate实现多租户的细节上做了解释,这次,我想带大家一起来使用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子句特性),实现多租户共享表。
<?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>
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;
……
}
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;
……
}
//实体管理器,管理实体持久化操作,通过容器注入
@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;
}
/**
* @author hanyi
* @MethodName : save
* @Description : 无返回值的泛型保存方法
* @param t:要保存的实体
*/
public void save(Object entity) {
//从实体类型中拿到当前操作的数据库名字
getDataBaseName(entity);
//取得实体管理器,进行持久化操作
getEntityManager().persist(entity);
}
到此eclipselink+ejb+jpa实现企业级的多租户应用的数据层隔离也就解决了。
版权声明:本文为博主原创文章,未经博主允许不得转载。
跟我上“云”端(四)使用eclipselink构建企业级多租户应用
原文:http://blog.csdn.net/hy6688_/article/details/47171885