数据层的多租户综述
多租户(Multi Tenancy/Tenant)是一种软件架构,其定义是:
在一台服务器上运行单个应用实例,它为多个租户提供服务。
在SaaS实施过程中,有一个显著的考量点,就是如何对应用数据进行设计,以支持多租户,而这种设计的思路,是要在数据的共享、安全隔离和性能间取得平衡。
传统的应用,仅仅服务于单个租户,数据库多部署在企业内部网络环境,对于数据拥有者来说,这些数据是自己“私有”的,它符合自己所定义的全部安全标准。而在云计算时代,随着应用本身被放到云端,导致数据层也经常被公开化,但租户对数据安全性的要求,并不因之下降。同时,多租户应用在租户数量增多的情况下,会比单租户应用面临更多的性能压力。本文即对这个主题进行探讨:多租户在数据层的框架如何在共享、安全与性能间进行取舍,同时了解一下市面上一些常见的数据厂商怎样实现这部分内容。
常见的三种模式
在 MSDN 的这篇文章 Multi-Tenant Data Architecture 中,系统的总结了数据层的三种多租户架构:
独立数据库
共享数据库、独立 Schema
共享数据库、共享 Schema、共享数据表
独立数据库是一个租户独享一个数据库实例,它提供了最强的分离度,租户的数据彼此物理不可见,备份与恢复都很灵活;共享数据库、独立 Schema 将每个租户关联到同一个数据库的不同 Schema,租户间数据彼此逻辑不可见,上层应用程序的实现和独立数据库一样简单,但备份恢复稍显复杂; 最后一种模式则是租户数据在数据表级别实现共享,它提供了最低的成本,但引入了额外的编程复杂性(程序的数据访问需要用 tenantId 来区分不同租户),备份与恢复也更复杂。这三种模式的特点可以用一张图来概括:
图 1. 三种部署模式的异同
上图所总结的是一般性的结论,而在常规场景下需要综合考虑才能决定那种方式是合适的。例如,在占用成本上,认为独立数据库会高,共享模式较低。但如果考虑到大租户潜在的数据扩展需求,有时也许会有相反的成本耗用结论。
而多租户采用的选择,主要是成本原因,对于多数场景而言,共享度越高,软硬件资源的利用效率更好,成本也更低。但同时也要解决好租户资源共享和隔离带来的安全与性能、扩展性等问题。毕竟,也有客户无法满意于将数据与其他租户放在共享资源中。
目前市面上各类数据厂商在多租户的支持上,大抵都是遵循上文所述的这几类模式,或者混合了几种策略,这部分内容将在下面介绍。
JPA Provider
JSR 338 定义了 JPA 规范 2.1,但如我们已经了解到的,Oracle 把多租户的多数特性推迟到了 Java EE 8 中。尽管这些曾经在 JavaOne 大会中有过演示,但无论是在 JPA 2.0(JSR 317)还是 2.1 规范中,都依然没有明文提及多租户。不过这并不妨碍一些 JPA provider 在这部分领域的实现,Hibernate 和 EclipseLink 已提供了全部或部分的多租户数据层的解决方案。
Hibernate 是当今最为流行的开源的对象关系映射(ORM)实现,并能很好地和 Spring 等框架集成,目前 Hibernate 支持多租户的独立数据库和独立 Schema 模式。EclipseLink 也是企业级数据持久层JPA标准的参考实现,对最新 JPA2.1 完整支持,在目前 JPA 标准尚未引入多租户概念之际,已对多租户支持完好,其前身是诞生已久、功能丰富的对象关系映射工具 Oracle TopLink。因此本文采用 Hibernate 和 EclipseLink 对多租户数据层进行分析。
Hibernate
Hibernate 是一个开放源代码的对象/关系映射框架和查询服务。它对 JDBC 进行了轻量级的对象封装,负责从 Java 类映射到数据库表,并从 Java 数据类型映射到 SQL 数据类型。在 4.0 版本 Hibenate 开始支持多租户架构——对不同租户使用独立数据库或独立 Sechma,并计划在 5.0 中支持共享数据表模式。
在 Hibernate 4.0 中的多租户模式有三种,通过 hibernate.multiTenancy 属性有下面几种配置:
NONE:非多租户,为默认值。
SCHEMA:一个租户一个 Schema。
DATABASE:一个租户一个 database。
DISCRIMINATOR:租户共享数据表。计划在 Hibernate5 中实现。
模式1:独立数据库
如果是独立数据库,每个租户的数据保存在物理上独立的数据库实例。JDBC 连接将指向具体的每个数据库,一个租户对应一个数据库实例。在 Hibernate 中,这种模式可以通过实现 MultiTenantConnectionProvider 接口或继承 AbstractMultiTenantConnectionProvider 类等方式来实现。三种模式中它的共享性最低,因此本文重点讨论以下两种模式。
模式 2:共享数据库,独立 Schema
对于共享数据库,独立 Schema。所有的租户共享一个数据库实例,但是他们拥有独立的 Schema 或 Catalog,本文将以多租户酒店管理系统为案例说明 Hibernate 对多租户的支持和用使用方法。
图 2. guest 表结构
这是酒店客户信息表,我们仅以此表对这种模式进行说明,使用相同的表结构在 MySQL 中创建 DATABASE hotel_1 和 hotel_2。基于 Schema 的多租户模式,需要在 Hibernate 配置文件 Hibernate.cfg.xml 中设置 hibernate.multiTenancy 等相关属性。
清单 1. 配置文件 Hibernate.cfg.xml
jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
root
com.mysql.jdbc.Driver
org.hibernate.dialect.MySQLInnoDBDialect
false
false
false
SCHEMA
hotel.dao.hibernate.TenantIdResolver
hotel.dao.hibernate.SchemaBasedMultiTenantConnectionProvider
属性规定了一个合约,以使 Hibernate 能够解析出应用当前的 tenantId,该类必须实现 CurrentTenantIdentifierResolver 接口,通常我们可以从登录信息中获得 tenatId。
清单 2. 获取当前 tenantId
public class TenantIdResolver implements CurrentTenantIdentifierResolver {
public String resolveCurrentTenantIdentifier() {
return Login.getTenantId();
}
}
< hibernate.multi_tenant_connection_provider> 属性指定了 ConnectionProvider,即 Hibernate 需要知道如何以租户特有的方式获取数据连接,SchemaBasedMultiTenantConnectionProvider 类实现了MultiTenantConnectionProvider 接口,根据 tenantIdentifier 获得相应的连接。在实际应用中,可结合使用 JNDI DataSource 技术获取连接以提高性能。
清单 3. 以租户特有的方式获取数据库连接
public class SchemaBasedMultiTenantConnectionProvider
implements MultiTenantConnectionProvider, Stoppable,
Configurable, ServiceRegistryAwareService {
private final DriverManagerConnectionProviderImpl connectionProvider
= new DriverManagerConnectionProviderImpl();
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = connectionProvider.getConnection();
connection.createStatement().execute("USE " + tenantIdentifier);
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection)
throws SQLException {
connection.createStatement().execute("USE test");
connectionProvider.closeConnection(connection);
}
……
}
与表 guest 对应的 POJO 类 Guest,其中主要是一些 getter 和 setter方法。
清单 4. POJO 类 Guest
@Table(name = "guest")
public class Guest {
private Integer id;
private String name;
private String telephone;
private String address;
private String email;
//getters and setters
……
}
我们使用 ServiceSchemaBasedMain.java 来进行测试,并假设了一些数据以方便演示,如当有不同租户的管理员登录后分别进行添加客户的操作。
清单 5. 测试类 ServiceSchemaBasedMain
public class ServiceSchemaBasedMain {
public static void main(String[] args) {
Session session = null;
Guest guest =null;
List list = null;
Transaction tx = null;
System.out.println("======== 租户 hotel_1 ========");
Login.setTenantId("hotel_1");
session = sessionFactory.openSession();
tx = session.beginTransaction();
guest = new Guest();
guest.setName("张三");
guest.setTelephone("56785678");
guest.setAddress("上海市张扬路88号");
guest.setEmail("[email protected] ");
session.saveOrUpdate(guest);
list = session.createCriteria(Guest.class).list();
for (Guest gue : list) {
System.out.println(gue.toString());
}
tx.commit();
session.close();
System.out.println("======== 租户 hotel_2 ========");
Login.setTenantId("hotel_2");
session = sessionFactory.openSession();
tx = session.beginTransaction();
guest = new Guest();
guest.setName("李四");
guest.setTelephone("23452345");
guest.setAddress("上海市南京路100号");
guest.setEmail("[email protected] ");
session.saveOrUpdate(guest);
list = session.createCriteria(Guest.class).list();
for (Guest gue : list) {
System.out.println(gue.toString());
}
tx.commit();
session.close();
}
}
清单 6. 运行程序 ServiceSchemaBasedMain 的输出
======== 租户 hotel_1 ========
Guest [id=1, name=Victor, telephone=56008888, address=上海科苑路399号, [email protected] ]
Guest [id=2, name=Jacky, telephone=66668822, address=上海金科路28号, [email protected] ]
Guest [id=3, name=张三, telephone=56785678, address=上海市张扬路88号, [email protected] ]
======== 租户 hotel_2 ========
Guest [id=1, name=Anton, telephone=33355566, address=上海南京路8号, [email protected] ]
Guest [id=2, name=Gus, telephone=33355566, address=北京大道3号, [email protected] ]
Guest [id=3, name=李四, telephone=23452345, address=上海市南京路100号, [email protected] ]
模式3:共享数据库、共享 Schema、共享数据表
在这种情况下,所有租户共享数据表存放数据,不同租户的数据通过 tenant_id 鉴别器来区分。但目前的 Hibernate 4 还不支持这个多租户鉴别器策略,要在 5.0 才支持。但我们是否有可选的替代方案呢?答案是使用 Hibernate Filter.
为了区分多个租户,我在 Schema 的每个数据表需要添加一个字段 tenant_id 以判定数据是属于哪个租户的。
图 3. 共享 Schema、共享数据表案例 E-R 图
根据上图在 MySQL 中创建 DATABASE hotel。
我们在 OR-Mapping 配置文件中使用了 Filter,以便在进行数据查询时,会根据 tenant_id 自动查询出该租户所拥有的数据。
清单 7. 对象关系映射文件 Room.hbm.xml
接下来我们在 HibernateUtil 类中通过 ThreadLocal 存放和获取 Hibernate Session,并将用户登录信息中的 tenantId 设置为 tenantFilterParam 的参数值。
清单 8. 获取 Hibernate Session 的工具类 HibernateUtil
public class HibernateUtil {
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
Session s = session.get();
if (s == null) {
s = sessionFactory.openSession();
String tenantId = LoginContext.getTenantId();
s.enableFilter("tenantFilter").setParameter("tenantFilterParam", tenantId);
session.set(s);
}
return s;
}
}
不过 Filter 只是有助于我们读取数据时显示地忽略掉 tenantId,但在进行数据插入的时候,我们还是不得不显式设置相应 tenantId 才能进行持久化。这种状况只能在 Hibernate5 版本中得到根本改变。
清单 9. 运行程序 HotelServiceMain 输出
======当前可用房间列表======
Room [ID=1, 房间编号=R1011, 位置=南楼, 床数=2, 状态=Free, 租户=新亚酒店]
Room [ID=7, 房间编号=R7011, 位置=南楼, 床数=2, 状态=Free, 租户=新亚酒店]
======预订后======
RentHistory [ID=1, 开始时间=2013-10-09 12:42:15.0, 结束时间=2013-10-12 12:42:15.0, Room ID=1, 房间编号=R1011, 房间状态=Booked, 金额=0.0元, 客人=Victor]
======结账后======
RentHistory [ID=1, 开始时间=2013-10-09 12:42:15.0, 结束时间=2013-10-12 12:42:15.0, Room ID=1, 房间编号=R1011, 房间状态=Free, 金额=300.0元, 客人=Victor]
多租户下的 Hibernate 缓存
基于独立 Schema 模式的多租户实现,其数据表无需额外的 tenant_id。通过 ConnectionProvider 来取得所需的 JDBC 连接,对其来说一级缓存(Session 级别的缓存)是安全的可用的,一级缓存对事物级别的数据进行缓存,一旦事物结束,缓存也即失效。但是该模式下的二级缓存是不安全的,因为多个 Schema 的数据库的主键可能会是同一个值,这样就使得 Hibernate 无法正常使用二级缓存来存放对象。例如:在 hotel_1 的 guest 表中有个 id 为 1 的数据,同时在 hotel_2 的 guest 表中也有一个 id 为 1 的数据。通常我会根据 id 来覆盖类的 hashCode() 方法,这样如果使用二级缓存,就无法区别 hotel_1 的 guest 和 hote_2 的 guest。
在共享数据表的模式下的缓存, 可以同时使用 Hibernate的一级缓存和二级缓存, 因为在共享的数据表中,主键是唯一的,数据表中的每条记录属于对应的租户,在二级缓存中的对象也具有唯一性。Hibernate 分别为 EhCache、OSCache、SwarmCache 和 JBossCache 等缓存插件提供了内置的 CacheProvider 实现,读者可以根据需要选择合理的缓存,修改 Hibernate 配置文件设置并启用它,以提高多租户应用的性能。
EclipseLink
EclipseLink 是 Eclipse 基金会管理下的开源持久层服务项目,为 Java 开发人员与各种数据服务(比如:数据库、web services、对象XML映射(OXM)、企业信息系统(EIS)等)交互提供了一个可扩展框架,目前支持的持久层标准中包括:
Java Persistence API (JPA)
Java Architecture for XML Binding (JAXB)
Java Connector Architecture (JCA)
Service Data Objects (SDO)
EclipseLink 前身是 Oracle TopLink, 2007年 Oracle 将后者绝大部分捐献给了 Eclipse 基金会,次年 EclipseLink 被 Sun 挑选成为 JPA 2.0 的参考实现。
注: 目前 EclipseLink2.5 完全支持 2013 年发布的 JPA2.1(JSR 338) 。
在完整实现 JPA 标准之外,针对 SaaS 环境,在多租户的隔离方面 EclipseLink 提供了很好的支持以及灵活地解决方案。
应用程序隔离
隔离的容器/应用服务器
共享容器/应用服务器的应用程序隔离
同一应用程序内的共享缓存但隔离的 entity manager factory
共享的 entity manager factory 但每隔离的 entity manager
数据隔离
隔离的数据库
隔离的Schema/表空间
隔离的表
共享表但隔离的行
查询过滤
Oracle Virtual Private Database (VPD)
对于多租户数据源隔离主要有以下方案
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子句特性),实现多租户共享表。
本节重点介绍多租户在 EclipseLink 中的共享数据表和一租户一个表的实现方法,并也以酒店多租户应用的例子展现共享数据表方案的具体实践。
EclipseLink Annotation @Multitenant
与 @Entity 或 @MappedSuperclass 一起使用,表明它们在一个应用程序中被多租户共享, 如清单 10。
清单10. @Multitenant
@Entity
@Table(name="room")
@Multitenant
...
publicclass Room {
}
表 1. Multitenant 包含两个属性
Annotation 属性
描述
缺省值
boolean includeCriteria
是否将租户限定应用到 select、update、delete 操作上
true
MultitenantType value
多租户策略,SINGLE_TABLE, TABLE_PER_TENANT, VPD.
SINGLE_TABLE
共享数据表(SINGLE_TABLE)
Metadata配置
依靠租户区分列修饰符 @TenantDiscriminatorColumn
实现。
清单11. @TenantDiscriminatorColumn
@Entity
@Table(name="hotel_guest")
@Multitenant(SINGLE_TABLE)
@TenantDiscriminatorColumn(name="tenant_id", contextProperty="tenant.id")
publicclass HotelGuest {
}
或者在EclipseLink描述文件orm.xml定义对象与表映射时进行限制,两者是等价的。
清单12. orm.xml
属性配置
租户区分列定义好后,在运行时环境需要配置具体属性值,以确定当前操作环境所属的租户。
三种方式的属性配置,按优先生效顺序排序如下
EntityManager(EM)
EntityManagerFactory(EMF)
Application context (when in a Java EE container)
例如 EntityManagerFactory 可以间接通过在 persistence.xml 中配置持久化单元(Persistence Unit)或直接传属性参数给初始化时 EntityManagerFactory。
清单 13. 配置 persistence.xml
或者
清单 14. 初始化 EntityManagerFactory
HashMap properties = new HashMap();
properties.put("tenant_id", "人力资源部");
...
EntityManager em = Persistence.createEntityManagerFactory("multi-tenant", properties).createEntityManager();
按共享粒度可以作如下区分,
用户需要通过 eclipselink.session-name 提供独立的会话名,确保每个租户占有独立的会话和缓存。
清单 15. 为 EntityManagerFactory 配置会话名
HashMap properties = new HashMap();
properties.put("tenant_id", "开发部");
properties.put("eclipselink.session-name", "multi-tenant-dev");
...
EntityManager em = Persistence.createEntityManagerFactory("multi-tenant", properties).createEntityManager();
共享的 EntityManagerFactory 级别
EntityManagerFactory 的默认模式, 此级别缺省配置为独立二级缓存(L2 cache), 即每个 mutlitenant 实体缓存设置为 ISOLATED,用户也可设置 eclipselink.multitenant.tenants-share-cache 属性为真以共享,此时多租户 Entity 缓存设置为 PROTECTED。
这种级别下,一个活动的 EntityManager 不能更换 tenantId。
这种级别下,共享 session,共享 L2 cache, 用户需要自己设置缓存策略,以设置哪些租户信息是不能在二级缓存共享的。
清单 16. 设置缓存
HashMap tenantProperties = new HashMap();
tenantProperties.put("tenant_id", "人力资源部");
HashMap cacheProperties = new HashMap();
cacheProperties.put("eclipselink.cache.shared.Employee", "false");
cacheProperties.put("eclipselink.cache.size.Address", "10");
cacheProperties.put("eclipselink.cache.type.Contract", "NONE");
...
EntityManager em = Persistence.createEntityManagerFactory("multi-tenant", cacheProperties).createEntityManager(tenantProperties);
同样,一个活动的EntityManager不能更换tenant ID。
几点说明:
每个表的区分列可以有任意多个,使用修饰符 TenantDiscriminatorColumns。
清单 17. 多个分区列
@TenantDiscriminatorColumns({
@TenantDiscriminatorColumn(name="tenant_id", contextProperty="tenant.id"),
@TenantDiscriminatorColumn(name = "guest_id", contextProperty="guest.id")
})
租户区分列的名字和对应的上下文属性名可以取任意值,由应用程序开发者设定。
生成的 Schema 可以也可以不包含租户区分列,如 tenant_id 或 guest_id。
租户区分列可以映射到实体对象也可以不。
注意:当映射的时候,实体对象相应的属性必须标记为只读(insertable=false, updatable=false),这种限制使得区分列不能作为实体表的 identifier。
TenantDiscriminatorColumn
被以下 EntityManager 的操作和查询支持:
persist,find,refresh,named queries,update all,delete all 。
一租户一表(TABLE_PER_TENANT )
这种多租户类型使每个租户的数据可以占据专属它自己的一个或多个表,多租户间的这些表可以共享相同 Schema 也可使用不同的,前者使用前缀(prefix)或后缀(suffix)命名模式的表的租户区分符,后者使用租户专属的 Schema 名来定义表的租户区分符。
Metadata配置
依靠数据表的租户区分修饰符 @TenantTableDiscriminator
实现
清单 18.
@Entity
@Table(name=“CAR”)
@Multitenant(TABLE_PER_TENANT)
@TenantTableDiscriminator(type=SCHEMA, contextProperty="eclipselink-tenant.id")
public class Car{
}
或
清单 19.
如前所述,TenantTableDiscriminatorType
有 3 种类型:SCHEMA、SUFFIX 和 PREFIX。
属性配置
与另外两种多租户类型一样,默认情况下,多租户共享EMF,如不想共享 EMF,可以通过配置 PersistenceUnitProperties.MULTITENANT_SHARED_EMF 以及 PersistenceUnitProperties.SESSION_NAME 实现。
清单 20.
// Shared EMF
EntityManager em = createEntityManager(MULTI_TENANT_PU);
em.getTransaction().begin();
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "RLT");
// Non shared EMF
HashMap properties = new HashMap();
properties.put(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, "false");
properties.put(PersistenceUnitProperties.SESSION_NAME, "non-shared-emf-for-rlt");
properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "RLT");
...
EntityManager em = Persistence.createEntityManagerFactory("multi-tenant-pu", properties).createEntityManager();
或在 persistence.xml 配置属性。
酒店多租户应用实例(EclipseLink 共享(单)表)
数据库 Schema 和测试数据与上文 Hibernate 实现相同,关于对象关系映射(OR mapping)的配置均采用 JPA 和 EclipseLink 定义的 Java Annotation 描述。
关于几个基本操作
添加一个对象实例, 利用EntityManager.persist()
清单 21. 添加
public void save(T t) {
em.persist(t);
}
public void saveBulk(List bulk) {
for(T t:bulk){
em.persist(t);
}
}
更新一个对象实例, 利用EntityManager.merge()
清单 22. 更新
public void update(T t){
em.merge(t);
}
查询, 利用EntityManager的NamedQuery,
清单 23. 多条件多结果查询
protected List queryResultList(String queryName, Class clazz, String[] argNames, Object[] argValues){
TypedQuery query = em.createNamedQuery(queryName, clazz);
if(argNames != null && argValues != null){
if(argNames.length != argValues.length){
return null;
}
for(int i = 0; i < argNames.length; i++){
query.setParameter(argNames[i], argValues[i]);
}
}
return query.getResultList();
}
若用 JPQL 实现则示例如下:
清单 24. JPQL NamedQuery 定义
@Entity
@Table(name = "rent_history")
@Multitenant
@TenantDiscriminatorColumn(name="tenant_id", contextProperty="tenant.id")
@NamedQueries({
@NamedQuery(
name="find_renthistory_by_hotel_guest_name",
query="select h from RentHistory h, HotelGuest g where h.hotelGuestId=g.id and g.name=:hotelGuestName order by h.createTime DESC"
),
})
public class RentHistory implements Serializable {
}
部分测试数据如下(MySQL):
hotel_admin
hotel_guest
room
运行附件 MT_Test_Hotels.zip 中的测试代码(请参照 readme)来看看多租户的一些典型场景。
清单 25. 运行测试代码
java -classpath build/classes/;D:/workspace/eclipselink/jlib/jpa/javax.persistence_2.1.0
.v201304241213.jar;D:/workspace/eclipselink/jlib/eclipselink.jar;D:/workspace/mysql/mysql-connector-java-5.1.26/mysql-connector-java-5.1.26-bin.jar mtsample.hotel.test.TestHotelAdmin
能得到输出片段如下:
清单 26. 输出
*****登录*****
用户名:letian
密码:
letian 已登录.
...
...
*****查房*****
1.获取可用房间
Room [id=3, categoryId=3, createTime=2013-09-22 23:13:11.0, position=南楼, serialNumber=R2011, status=Free]
Room [id=4, categoryId=4, createTime=2013-09-24 09:07:02.0, position=北楼, serialNumber=R2012, status=Free]
...
...
*****入住*****
请输入房间号:R2012
请输入房客编号:4
请输入入住时间(yyyy.MM.dd H:mm):2014.02.14 14:02
请输入退房时间(yyyy.MM.dd H:mm):2014.02.17 11:00
...
...
*****查房*****
1.获取可用房间
Room [id=3, categoryId=3, createTime=2013-09-26 13:02:49.0, position=南楼, serialNumber=R2011, status=Free]
...
...
*****退房*****
请输入房间号:R2012
请输入退房时间(yyyy.MM.dd H:mm):2014.02.15 5:20
...
...
1.获取所有入住历史信息
RentHistory [id=3, amount=260.0, createTime=2013-09-26 13:07:48.0, endTime=Sat Feb 15 05:20:00 CST 2014, hotelGuestId=4, roomId=4, startTime=Fri Feb 14 14:02:00
CST 2014, ]
RentHistory [id=1, amount=1040.0, createTime=2013-09-17 13:28:00.0, endTime=Fri Sep 20 11:28:00 CST 2013, hotelGuestId=3, roomId=3, startTime=Wed Sep 18 13:28:00 CST 2013, ]
...
...
*****查房*****
1.获取可用房间
Room [id=3, categoryId=3, createTime=2013-09-26 13:02:49.0, position=南楼, serialNumber=R2011, status=Free]
Room [id=4, categoryId=4, createTime=2013-09-26 13:07:48.0, position=北楼, serialNumber=R2012, status=Free]
通过共享表的测试数据以及运行结果可以看到,对于多个不同的租户(hotel_admin),在添加、查找、更新操作没有显示声明租户标识的情况下,EntityManager 可以根据自身的租户属性配置
实现租户分离。在本实例,EntityManager 初始化时利用到 hotel_admin 登录后的会话上下文进行租户判断,这里不再赘述。
注:上文中提及的全部源码都可以在附件中找到。
其它方面的考虑
数据备份
独立数据库和独立Sechma的模式,为每个租户备份数据比较容易,因为他们存放在不同的数据表中,只需对整个数据库或整个Schema进行备份。
在共享数据表的模式下,可以将所有租户的数据一起备份,但是若要为某一个租户或按租户分开进行数据备份,就会比较麻烦。通常需要另外写sql脚本根据tenant_id来取得对应的数据然后再备份,但是要按租户来导入的话依然比较麻烦,所以必要时还是需要备份所有并为以后导入方便。
性能
独立数据库:性能高,但价格也高,需要占用资源多,不能共享,性价比低。
共享数据库,独立 Schema:性能中等,但价格合适,部分共享,性价比中等。
共享数据库,共享 Schema,共享数据表:性能中等(可利用 Cache 可以提高性能),但价格便宜,完全共享,性价比高。如果在某些表中有大量的数据,可能会对所有租户产生性能影响。
对于共享数据库的情况下,如果因为太多的最终用户同时访问数据库而导致应用程序性能问题,可以考虑数据表分区等数据库端的优化方案。
经济考虑
为了支持多租户应用,共享模式的应用程序往往比使用独立数据库模式的应用程序相对复杂,因为开发一个共享的架构,导致在应用设计上得花较大的努力,因而初始成本会较高。然而,共享模式的应用在运营成本上往往要低一些,每个租户所花的费用也会比较低。
结束语
多租户数据层方案的选择是一个综合的考量过程,包括成本、数据隔离与保护、维护、容灾、性能等。但无论怎样选择,OR-Mapping 框架对多租户的支持将极大的解放开发人员的工作,从而可以更多专注于应用逻辑。最后我们以一个 Hibernate 和 EclipseLink 的比较来结束本文。
你可能感兴趣的:(云计算平台)
Azure 基础
SmallFatMan
# Azure azure microsoft 运维 linux 服务器 学习 面试
Azure基础一、Azure基础知识简介二、云计算简介?三、责任共担四、你始终负责:五、云服务提供商始终负责:六、云模型1、私有云2、公有云3、混合云4、多云一、Azure基础知识简介MicrosoftAzure是一个云计算平台,提供一系列不断扩展的服务,可帮助你构建解决方案来满足业务目标。Azure服务支持从简单到复杂的一切内容。Azure具有简单的Web服务,用于在云中托管业务。Azure还支
OpenStack认证服务(Keystone)详细解读
D3Zane
OpenStack openstack 服务器 运维
文章目录前言一、项目陈述二、Keystone的基本名词概念三、相关概念关系解释三、Keystone的组件架构四、Keystone认证的基本步骤总结前言OpenStack云计算平台的组件有很多,该先安装哪个组件呢?为什么要先安装它?一、项目陈述由于OpenStack云计算平台是由众多组件构成的一套复杂系统,哪些组件被允许连入系统、进入系统后允许使用其他哪些组件功能,都需要一个认证单元去判断和决定。K
华为云计算平台架构介绍
单车~
算法 数据结构
在当今数字化时代,云计算已成为企业实现数字化转型和创新发展的关键支撑技术。华为作为全球领先的信息与通信技术(ICT)解决方案供应商,凭借先进的技术和创新的设计,其云计算平台架构为用户提供了高效、可靠、安全且灵活的云计算服务。一、总体架构概述华为云计算平台架构秉持分层设计的理念,涵盖了基础设施层(IaaS)、平台层(PaaS)以及应用层(SaaS)。这样的分层架构,能够让各层实现独立的扩展与优化,并
大数据分析与安全分析
Zh&&Li
网络安全运维 数据分析 安全 数据挖掘 运维 数据库
大数据分析一、大数据安全威胁与需求分析1.1大数据相关概念发展大数据:是指非传统的数据处理工具的数据集大数据特征:海量的数据规模、快速的数据流转、多样的数据类型和价值密度低等大数据的种类和来源非常多,包括结构化、半结构化和非结构化数据有关大数据的新兴网络信息技术应用不断出现,主要包括大规模数据分析处理、数据挖掘、分布式文件系统、分布式数据库、云计算平台、互联网和存储系统1.2大数据安全威胁分析“数
如何进行 AWS 云监控
ManageEngine卓豪
云安全 云监控 AWS AWS 云安全 云监控 AWS云监控
什么是AWS?AmazonWebServices(AWS)是Amazon提供的一个全面、广泛使用的云计算平台。它提供广泛的云服务,包括计算能力、存储选项、网络功能、数据库、分析、机器学习、人工智能、物联网和安全。使用AWS有哪些好处?使用AWS可为企业提供可扩展性、成本效益、可靠性、安全性、灵活性、全球覆盖和创新等。凭借对计算资源的按需访问、即用即付定价、全球基础设施、强大的安全功能以及广泛的服务
目前支持云计算的有哪些厂家?
江河之流
计算机的工具开发 #专升本 #改善自己的生活方式 云计算
目前市场上提供云计算服务的厂家众多,以下是一些主要的云计算服务提供商:1.**亚马逊网络服务(AmazonWebServices,AWS)**:全球市场份额最大的云服务提供商。2.**微软Azure**:微软提供的云计算平台,提供全面的云服务和解决方案。3.**谷歌云平台(GoogleCloudPlatform,GCP)**:谷歌提供的云计算服务,以其强大的数据分析和机器学习能力著称。4.**阿里
在亚马逊云科技上搭建云原生生成式AI教育学习平台
佛州小李哥
AWS技术 科技 云原生 人工智能 云计算 架构 aws 亚马逊云科技
项目简介:小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案,帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWSAI最佳实践,并应用到自己的日常工作里。本次介绍的是如何利用亚马逊云科技大模型托管服务AmazonBedrock和云原生容器管理服务,将生成式AI和亚马逊Titan大模型应用到教育和学习场景,利用Titan大模型的向量化、文字和图片生成能力构建云端
AWS账号可以人民币付款吗
九河云
aws 云计算
在当今数字经济时代,云计算服务越来越受到企业和个人的青睐。亚马逊云服务作为全球领先的云计算平台,提供了丰富的服务选项和灵活的计费方式。然而,对于中国用户来说,是否可以使用人民币进行付款仍然是一个重要的问题。本文将由九河云详细探讨AWS账户的付款方式及其对人民币支付的支持情况。一、AWS的付款方式AWS支持多种付款方式,以满足全球用户的需求。常见的付款方式包括:1.信用卡/借记卡:这是最普遍的付款方
《Hadoop核心技术》作者翟周伟 :我与Hadoop的不解之缘
xytlwp
翟周伟 hadoop 数据挖掘 自然语言处理 hadoop 翟周伟 数据挖掘 自然语言处理
摘要:翟周伟,资深Hadoop技术专家,《Hadoop开源云计算平台》、《Hadoop核心技术》作者。日前,CSDN记者对他进行了采访,请他解读Hadoop发展现状、特性及发展前景,以及这一路走来的心路历程。翟周伟,资深Hadoop技术专家,专注于Hadoop&大数据,数据挖掘,自然语言处理领域,目前就职于百度。2009年,利用Hadoop构建商业级大数据系统,是国内该领域最早的一批人之一;负责设
阿里云力夺 FewCLUE 榜首!知识融入预训练+小样本学习的实战解析
阿里云技术
自然语言处理 机器学习
一概述7月8日,中文语言理解权威评测基准CLUE公开了中文小样本学习评测榜单最新结果,阿里云计算平台PAI团队携手达摩院智能对话与服务技术团队,在大模型和无参数限制模型双赛道总成绩第一名,决赛答辩总成绩第一名。中文语言理解权威评测基准CLUE自成立以来发布了多项NLP评测基准,包括分类榜单,阅读理解榜单和自然语言推断榜单等,在学术界、工业界产生了深远影响。其中,FewCLUE是CLUE最新推出的一
OpenStack云计算平台实战
港南四大炮亡
openstack 云计算
项目一任务一了解云计算目前主流的开源云计算平台如下:OpenStack。OpenStack是一个提供IAAS开源解决方案的全球性项目,由Rackspace公司和NASA共同创办,采用了Apache2.0许可证,可以随意使用。OpenStack并不要求使用专门的硬件和软件,可以在虚拟系统或裸机系统中运行。它支持多种虚拟机管理器(KVM和XenServer)和容器技术。OpenStack适应不同的用户
在亚马逊云科技上利用生成式AI开发用户广告营销平台
佛州小李哥
AWS技术 科技 人工智能 aws 架构 亚马逊云科技 云计算 开发
项目简介:小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案,帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWSAI最佳实践,并应用到自己的日常工作里。本次介绍的是如何利用亚马逊云科技大模型托管服务AmazonBedrock和个性化推荐算法服务AmazonPersonalize搭建面向用户的广告营销平台,将生成式AI应用到用户的广告营销场景,提升用户产品转化
2022年河南省高等职业教育技能大赛云计算赛项竞赛赛卷(样卷)
忘川_ydy
云计算 云计算 openstack kubernetes docker python k8s ansible
#需要资源(软件包及镜像)或有问题的,可私博主!!!#需要资源(软件包及镜像)或有问题的,可私博主!!!#需要资源(软件包及镜像)或有问题的,可私博主!!!第一部分:私有云任务1私有云服务搭建(10分)使用提供的用户名密码,登录竞赛用的云计算平台,按要求自行使用镜像创建两台云主机,创建完云主机后确保网络正常通信,然后按要求配置服务器。根据提供安装脚本框架,补充脚本完成OpenStack平台的安装搭
云计算拼的是运维吗
ddddwd--1
云计算 运维
云计算拼的是运维吗?云计算并不仅仅是拼运维,还有其他方面也很重要。在云计算中,运维确实是一个重要的方面。运维涉及管理和维护云基础设施、服务器、网络和存储等组件,以确保它们的正常运行、高可用性和安全性。运维人员负责监控、维护、更新和修复云基础设施,以满足用户的需求并确保服务的可靠性。然而,云计算不仅仅依赖于运维,还包括其他重要的方面,如:资源管理和调度:云计算平台需要有效地管理和调度计算资源,以满足
F5漏洞复现[CVE-2020-5902]与[CVE_2021_22986]
Coder_preston
计算机安全 pytorch git branch
引言 F5BIG-IP广泛应用于大型企业,数据中心、云计算平台中,可以实现应用加速、负载均衡、SLL过载、web应用防火墙等功能。这篇文章主要是复现F5的漏洞,包括其被远程代码执行的过程,以及探究以下我们可以在F5上远程执行代码之后可以做哪些事情。环境搭建 F5的环境搭建教程在网上可以查到很多,这里大概介绍以下流程与心得。首先搭建环境需要使用vmware软件运行F5的镜像来实现,需要下载并安装相关
阿里云计算平台大数据基础工程技术团队直聘!!!
大数据
大数据基础工程技术团队,隶属于阿里云智能集团计算平台事业部,是一支负责阿里集团、公共云和混合云场景计算平台大数据&AI产品的稳定性建设、架构&成本优化、运维产品ABM(ApsaraBigdataManager)研发和售后技术专家支持的团队。通过软件工程,数据智能化的方法论,围绕数据系统化建设运维智能工具链,打造飞天大数据&AI运维管控平台ABM,解决超大规模分布式集群运维管理问题,提升产品的稳定性
2017全球十大云计算平台市场占有率排行榜
weixin_34418883
java 数据库
从Google首席执行官埃里克·施密特(EricSchmidt)首次提出“云计算”(cloudcomputing)的概念到现在,云计算已经走过了炒作期和实践期,已经处于成熟期。同时,行业集中度也越来越高并呈逐渐加强的趋势,目前业内大公司已经占据了整个市场的半壁江山。SynergyResearchGroup根据2017年市场占有率的多少和市场增长率的快慢对全球几大云计算平台进行了调查和排名,亚马逊A
混合云网络建设
杰克逊的日记
网络
一、基础信息1.实验信息实验名称:混合云网络建设实验级别:进阶实验时长:2小时2.实验目的1、掌握混合云网络的建设流程3.实验环境实验平台:公有云+本地数据中心IDC4.前置技能有阿里云公有云账号,会开通vpc实例,ecs实例等5.实验介绍小智是一家公司的云计算助理工程师。在公司部署的云计算平台下,小智需要学习如何搭建混合云网络建设,以便后续能够快速上手进行混合云网络建设。本实验主要介绍,并进行操
亚马逊认证考试系列 - 知识点 - EBS简介
customservice
考试专栏 - AWS aws 云计算 学习 IT认证 认证考试
介绍在AWS云计算平台中,弹性块存储(ElasticBlockStore,EBS)扮演着至关重要的角色,为云上的应用程序提供了可靠的持久性块存储。EBS提供了高度可扩展性和可靠性,使得用户可以根据应用的需求轻松地扩展存储容量并保证数据的安全性。这一点在故障恢复和业务连续性方面尤为重要。以一些真实的使用案例来说明这些特性的重要性,例如在某个区域的故障中如何使用EBS来保持应用的高可用性。举例来说,假
OpenStack之仪表盘服务(Dashboard)
我不是少爷.
OpenStack平台部署 openstack
一)Dashboard的基本1.概念OpenStack云计算平台可以通过命令行管理工具使用,或者其他应用通过应用程序接口被其他程序调用。但是都较为麻烦,不够直观,那么Dashboard随机应运而生了,其本质是一个web前端控制台,主要功能是让用户通过在网页上的操作完成对云计算平台的配置与管理。2.组织架构Dashboard是一个用Python编写的支持WSGI协议的网络应用,部署在Apache服务
如何利用边缘计算网关进行机床数据采集,以提高数据采集的效率和准确性-天拓四方
北京天拓四方科技股份有限公司
其他 物联网
边缘计算网关集成了数据采集、处理和传输功能的嵌入式设备。它位于传感器和执行器组成的设备层与云计算平台之间,能够实时处理和响应本地设备的数据请求,减轻云平台的压力,提高数据处理的速度和效率。同时,边缘计算网关还可以将处理后的数据上传至云平台,为远程监控和分析提供支持。随着工业4.0和智能制造的快速发展,机床作为制造行业的重要设备,其数据采集与分析对于提升生产效率、保证产品质量、优化加工过程具有重要意
云计算关键技术
夜夜流光相皎洁_小宁
网络安全 # 云计算安全 云计算 云计算安全 网络安全
目录一、云计算关键技术概述1.1概述二、关键技术内容2.1虚拟化技术2.2分布式数据存储技术2.3资源管理技术2.4云计算平台管理技术2.5多租户隔离技术2.5.1多租户技术下SaaS特征2.5.2多租户技术面临的技术难题2.5.2.1数据隔离2.5.2.2客户化配置2.5.2.3架构扩展2.5.2.4性能定制一、云计算关键技术概述1.1概述云计算的实现采用分层架构,其中的关键技术包括虚拟化技术、
最全的微服务知识科普
董鹏dp
微信公众号:内核小王子关注可了解更多关于数据库,JVM内核相关的知识;如果你有任何疑问也可以加我pigpdong[^1]微服务好处:实现跨团队的解藕,实现更高的并发(目前单机只能实现c10k)不用在拷贝代码,基础服务可以公用,更好的支持服务治理,能够更好的兼容云计算平台。imageRPCrpc:向调用本地方法一样调用远程函数客户端:一般利用动态代理生成一个接口的实现类,在这个实现类里通过网络把接口
AWS 云监控工具
ManageEngine卓豪
云监控 aws 云计算 云服务平台 云监控
AmazonWebServices(AWS)是Amazon提供的云计算平台,为企业提供技术服务,包括计算能力、存储和数据库。借助AWS,企业无需购买、拥有或维护物理数据中心和服务器,而AWS的即用即付方法使企业能够避免与IT基础设施相关的高成本。但是,AWS上托管的应用程序和数据库会以AWS云日志和事件的形式生成大量数据。为了优化性能、资源利用率和威胁缓解,管理员需要使用高效的AWS云监控工具持续
基于腾讯云服务器搭建幻兽帕鲁服务器保姆级教程
老王说主机
腾讯云 幻兽帕鲁 Palworld
随着网络游戏的普及,越来越多的玩家希望能够拥有自己的游戏服务器,以便能够自由地玩耍。而腾讯云服务器作为一个优秀的云计算平台,为玩家们提供了一个便捷、稳定、安全的游戏服务器解决方案。本文将为大家介绍如何基于腾讯云服务器搭建幻兽帕鲁服务器,希望对大家有所帮助。一、搭建步骤以下搭建教程将基于腾讯云轻量应用服务器Lighthouse来进行,腾讯云官方为大家提供了自动部署幻兽帕鲁、自动放通防火墙端口等,无需
云原生:改变产品、架构与商业模式的未来引领者
快乐非自愿
云原生 架构 低代码 物联网
本文探讨了云原生的概念、创新以及在产品、架构和商业模式中的应用。云原生以其敏捷、可扩展和资源高效利用的特性,成为了引领未来的技术趋势。通过云原生的应用,企业可以实现更快速的产品交付,更高效的架构设计,并重新定义商业模式。随着云计算的快速发展,云原生作为一种创新的软件开发和部署范式,逐渐成为了技术界的热门话题。云原生不仅仅是一种技术,更是一种思想的转变,通过充分利用云计算平台的特性,将应用程序打包成
赋能未来社区:数据中台智慧园区的全方位解决方案_光点科技
光点数据治理
科技
在信息技术与互联网快速发展的今天,传统的园区管理方式已无法满足时代对效率与智能化的追求。数据中台作为企业数字化转型的核心,正引领着智慧园区的发展趋势。一个集成了数据中台的智慧园区,不仅能有效地整合资源,优化管理流程,还能为园区企业和居住人群提供更加智能、便捷的服务体验。但如何构建一个高效的“数据中台智慧园区”呢?本篇文章将为您揭晓。数据中台:园区智能核心数据中台是建立在云计算平台之上的数据资源管理
前端-云点播技术
软件测试李同学
测试开发-VUE 前端 云计算 与点播 视频播放 视频
一、简介云点播(CloudVideoOnDemand)是一种基于云计算平台提供的视频点播服务。这种服务允许用户在需要的时候按需观看视频内容,而无需等待下载完成。以下是一些关于云点播技术的常见特征和要点:存储和管理:云存储:视频文件通常存储在云存储服务中,例如阿里云对象存储、亚马逊S3等。文件管理:提供对视频文件的管理功能,包括上传、删除、编辑和组织。视频转码:格式转换:云点播服务通常支持自动转码,
阿里云开源大数据产品年度发布
Apache Spark中国社区
阿里云 开源 大数据 云计算
本文整理自阿里云计算平台事业部开源大数据产品总监陈守元在2023云栖大会开源大数据专场的分享,演讲主题为阿里云开源大数据产品年度发布。随着云计算的不断发展,未来数据处理和应用的趋势将围绕CloudNative、Severless和Data+AI展开。其中,云原生架构已成为主流趋势,因为它可以提高数据处理和应用程序的可伸缩性和灵活性,支持大规模部署和更快的响应时间。同时,Serverless作为一种
深入探究 Linux 系统中的 SELinux
嵌入式胖哥
linux 运维 服务器
在当前数字化时代,信息安全成为了至关重要的问题。Linux操作系统,以其开源的特性和灵活性,成为了许多服务器、嵌入式设备和云计算平台的首选操作系统。然而,由于其开放性,也为系统安全性带来了一些挑战。为提高Linux系统的安全性,SELinux(Security-EnhancedLinux)应运而生。本文将深入探究SELinux在Linux系统中的作用、原理和使用方法,并逐一讨论其在保护系统安全方面
html
周华华
html
js
1,数组的排列
var arr=[1,4,234,43,52,];
for(var x=0;x<arr.length;x++){
for(var y=x-1;y<arr.length;y++){
if(arr[x]<arr[y]){
&
【Struts2 四】Struts2拦截器
bit1129
struts2拦截器
Struts2框架是基于拦截器实现的,可以对某个Action进行拦截,然后某些逻辑处理,拦截器相当于AOP里面的环绕通知,即在Action方法的执行之前和之后根据需要添加相应的逻辑。事实上,即使struts.xml没有任何关于拦截器的配置,Struts2也会为我们添加一组默认的拦截器,最常见的是,请求参数自动绑定到Action对应的字段上。
Struts2中自定义拦截器的步骤是:
make:cc 命令未找到解决方法
daizj
linux 命令未知 make cc
安装rz sz程序时,报下面错误:
[root@slave2 src]# make posix
cc -O -DPOSIX -DMD=2 rz.c -o rz
make: cc:命令未找到
make: *** [posix] 错误 127
系统:centos 6.6
环境:虚拟机
错误原因:系统未安装gcc,这个是由于在安
Oracle之Job应用
周凡杨
oracle job
最近写服务,服务上线后,需要写一个定时执行的SQL脚本,清理并更新数据库表里的数据,应用到了Oracle 的 Job的相关知识。在此总结一下。
一:查看相关job信息
1、相关视图
dba_jobs
all_jobs
user_jobs
dba_jobs_running 包含正在运行
多线程机制
朱辉辉33
多线程
转至http://blog.csdn.net/lj70024/archive/2010/04/06/5455790.aspx
程序、进程和线程:
程序是一段静态的代码,它是应用程序执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。线程是比进程更小的单位,一个进程执行过程中可以产生多个线程,每个线程有自身的
web报表工具FineReport使用中遇到的常见报错及解决办法(一)
老A不折腾
web报表 finereport java报表 报表工具
FineReport使用中遇到的常见报错及解决办法(一)
这里写点抛砖引玉,希望大家能把自己整理的问题及解决方法晾出来,Mark一下,利人利己。
出现问题先搜一下文档上有没有,再看看度娘有没有,再看看论坛有没有。有报错要看日志。下面简单罗列下常见的问题,大多文档上都有提到的。
1、address pool is full:
含义:地址池满,连接数超过并发数上
mysql rpm安装后没有my.cnf
林鹤霄
没有my.cnf
Linux下用rpm包安装的MySQL是不会安装/etc/my.cnf文件的,
至于为什么没有这个文件而MySQL却也能正常启动和作用,在这儿有两个说法,
第一种说法,my.cnf只是MySQL启动时的一个参数文件,可以没有它,这时MySQL会用内置的默认参数启动,
第二种说法,MySQL在启动时自动使用/usr/share/mysql目录下的my-medium.cnf文件,这种说法仅限于r
Kindle Fire HDX root并安装谷歌服务框架之后仍无法登陆谷歌账号的问题
aigo
root
原文:http://kindlefireforkid.com/how-to-setup-a-google-account-on-amazon-fire-tablet/
Step 4: Run ADB command from your PC
On the PC, you need install Amazon Fire ADB driver and instal
javascript 中var提升的典型实例
alxw4616
JavaScript
// 刚刚在书上看到的一个小问题,很有意思.大家一起思考下吧
myname = 'global';
var fn = function () {
console.log(myname); // undefined
var myname = 'local';
console.log(myname); // local
};
fn()
// 上述代码实际上等同于以下代码
m
定时器和获取时间的使用
百合不是茶
时间的转换 定时器
定时器:定时创建任务在游戏设计的时候用的比较多
Timer();定时器
TImerTask();Timer的子类 由 Timer 安排为一次执行或重复执行的任务。
定时器类Timer在java.util包中。使用时,先实例化,然后使用实例的schedule(TimerTask task, long delay)方法,设定
JDK1.5 Queue
bijian1013
java thread java多线程 Queue
JDK1.5 Queue
LinkedList:
LinkedList不是同步的。如果多个线程同时访问列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方
http认证原理和https
bijian1013
http https
一.基础介绍
在URL前加https://前缀表明是用SSL加密的。 你的电脑与服务器之间收发的信息传输将更加安全。
Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后
【Java范型五】范型继承
bit1129
java
定义如下一个抽象的范型类,其中定义了两个范型参数,T1,T2
package com.tom.lang.generics;
public abstract class SuperGenerics<T1, T2> {
private T1 t1;
private T2 t2;
public abstract void doIt(T
【Nginx六】nginx.conf常用指令(Directive)
bit1129
Directive
1. worker_processes 8;
表示Nginx将启动8个工作者进程,通过ps -ef|grep nginx,会发现有8个Nginx Worker Process在运行
nobody 53879 118449 0 Apr22 ? 00:26:15 nginx: worker process
lua 遍历Header头部
ronin47
lua header 遍历
local headers = ngx.req.get_headers()
ngx.say("headers begin", "<br/>")
ngx.say("Host : ", he
java-32.通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小(两数组的差最小)。
bylijinnan
java
import java.util.Arrays;
public class MinSumASumB {
/**
* Q32.有两个序列a,b,大小都为n,序列元素的值任意整数,无序.
*
* 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
* 例如:
* int[] a = {100,99,98,1,2,3
redis
开窍的石头
redis
在redis的redis.conf配置文件中找到# requirepass foobared
把它替换成requirepass 12356789 后边的12356789就是你的密码
打开redis客户端输入config get requirepass
返回
redis 127.0.0.1:6379> config get requirepass
1) "require
[JAVA图像与图形]现有的GPU架构支持JAVA语言吗?
comsci
java语言
无论是opengl还是cuda,都是建立在C语言体系架构基础上的,在未来,图像图形处理业务快速发展,相关领域市场不断扩大的情况下,我们JAVA语言系统怎么从这么庞大,且还在不断扩大的市场上分到一块蛋糕,是值得每个JAVAER认真思考和行动的事情
安装ubuntu14.04登录后花屏了怎么办
cuiyadll
ubuntu
这个情况,一般属于显卡驱动问题。
可以先尝试安装显卡的官方闭源驱动。
按键盘三个键:CTRL + ALT + F1
进入终端,输入用户名和密码登录终端:
安装amd的显卡驱动
sudo
apt-get
install
fglrx
安装nvidia显卡驱动
sudo
ap
SSL 与 数字证书 的基本概念和工作原理
darrenzhu
加密 ssl 证书 密钥 签名
SSL 与 数字证书 的基本概念和工作原理
http://www.linuxde.net/2012/03/8301.html
SSL握手协议的目的是或最终结果是让客户端和服务器拥有一个共同的密钥,握手协议本身是基于非对称加密机制的,之后就使用共同的密钥基于对称加密机制进行信息交换。
http://www.ibm.com/developerworks/cn/webspher
Ubuntu设置ip的步骤
dcj3sjt126com
ubuntu
在单位的一台机器完全装了Ubuntu Server,但回家只能在XP上VM一个,装的时候网卡是DHCP的,用ifconfig查了一下ip是192.168.92.128,可以ping通。
转载不是错:
Ubuntu命令行修改网络配置方法
/etc/network/interfaces打开后里面可设置DHCP或手动设置静态ip。前面auto eth0,让网卡开机自动挂载.
1. 以D
php包管理工具推荐
dcj3sjt126com
PHP Composer
http://www.phpcomposer.com/
Composer是 PHP 用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件。
中文文档
入门指南
下载
安装包列表
Composer 中国镜像
Gson使用四(TypeAdapter)
eksliang
json gson Gson自定义转换器 gsonTypeAdapter
转载请出自出处:http://eksliang.iteye.com/blog/2175595 一.概述
Gson的TypeAapter可以理解成自定义序列化和返序列化 二、应用场景举例
例如我们通常去注册时(那些外国网站),会让我们输入firstName,lastName,但是转到我们都
JQM控件之Navbar和Tabs
gundumw100
html xml css
在JQM中使用导航栏Navbar是简单的。
只需要将data-role="navbar"赋给div即可:
<div data-role="navbar">
<ul>
<li><a href="#" class="ui-btn-active&qu
利用归并排序算法对大文件进行排序
iwindyforest
java 归并排序 大文件 分治法 Merge sort
归并排序算法介绍,请参照Wikipeida
zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F
基本思想:
大文件分割成行数相等的两个子文件,递归(归并排序)两个子文件,直到递归到分割成的子文件低于限制行数
低于限制行数的子文件直接排序
两个排序好的子文件归并到父文件
直到最后所有排序好的父文件归并到输入
iOS UIWebView URL拦截
啸笑天
UIWebView
本文译者:candeladiao,原文:URL filtering for UIWebView on the iPhone说明:译者在做app开发时,因为页面的javascript文件比较大导致加载速度很慢,所以想把javascript文件打包在app里,当UIWebView需要加载该脚本时就从app本地读取,但UIWebView并不支持加载本地资源。最后从下文中找到了解决方法,第一次翻译,难免有
索引的碎片整理SQL语句
macroli
sql
SET NOCOUNT ON
DECLARE @tablename VARCHAR (128)
DECLARE @execstr VARCHAR (255)
DECLARE @objectid INT
DECLARE @indexid INT
DECLARE @frag DECIMAL
DECLARE @maxfrag DECIMAL
--设置最大允许的碎片数量,超过则对索引进行碎片
Angularjs同步操作http请求with $promise
qiaolevip
每天进步一点点 学习永无止境 AngularJS 纵观千象
// Define a factory
app.factory('profilePromise', ['$q', 'AccountService', function($q, AccountService) {
var deferred = $q.defer();
AccountService.getProfile().then(function(res) {
hibernate联合查询问题
sxj19881213
sql Hibernate HQL 联合查询
最近在用hibernate做项目,遇到了联合查询的问题,以及联合查询中的N+1问题。
针对无外键关联的联合查询,我做了HQL和SQL的实验,希望能帮助到大家。(我使用的版本是hibernate3.3.2)
1 几个常识:
(1)hql中的几种join查询,只有在外键关联、并且作了相应配置时才能使用。
(2)hql的默认查询策略,在进行联合查询时,会产
struts2.xml
wuai
struts
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache