云架构:hibernate4已经支持多租户了,但是如何创建表?
沙舟狼客
2016-06-22
多租户分三种设计:
1.一个应用对应一个数据库。完全的物理隔离!每个用户一套系统! 2.所有用户公用一个应用但是不同的数据库(schme) 3.所有用户公用一个应用。一个数据库 目前我采用的是第二种设计 hibernat额配置 <prop key="hibernate.multiTenancy">SCHEMA</prop> <!--<prop key="hibernate.multiTenancy">DATABASE</prop>--> <prop key="hibernate.tenant_identifier_resolver">cutdb.hb.TenantIdResolver</prop> <prop key="hibernate.multi_tenant_connection_provider"> cutdb.hb.SchemaBasedMultiTenantConnectionProvider </prop> 自己实现tenant_identifier_resolver和multi_tenant_connection_provider SchemaBasedMultiTenantConnectionProvider代码 package cutdb.hb; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.cfg.Environment; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl; import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Marker; import org.slf4j.MarkerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; /** * Created by trq on 2016/6/20. * DriverManagerdatasourceConnectionProviderImpl类是直接读取hibernate配置文件的, * 而DatasourcedatasourceConnectionProviderImpl是能够读取spring配置文件中的DataSource。 */ public class SchemaBasedMultiTenantConnectionProvider implements MultiTenantConnectionProvider, ServiceRegistryAwareService { private static Logger logger = LoggerFactory.getLogger(SchemaBasedMultiTenantConnectionProvider.class); private DatasourceConnectionProviderImpl datasourceConnectionProvider = new DatasourceConnectionProviderImpl(); public Connection getAnyConnection() throws SQLException { return datasourceConnectionProvider.getConnection(); } public void releaseAnyConnection(Connection connection) throws SQLException { datasourceConnectionProvider.closeConnection(connection); } private void useDb(String dbName, Connection connection) { try { PreparedStatement ps = connection.prepareStatement("SELECT count(sc.SCHEMA_NAME) FROM information_schema.SCHEMATA sc where sc.SCHEMA_NAME=?"); ps.setString(1, dbName); ResultSet rs = ps.executeQuery(); if (rs.next()) { if (rs.getInt(1) == 0) { connection.createStatement().execute("create database "+dbName+" DEFAULT character set utf8"); } } connection.createStatement().execute("use " + dbName); } catch (SQLException e) { e.printStackTrace(); } } public Connection getConnection(String tenantIdentifier) throws SQLException { final Connection connection = getAnyConnection(); useDb(tenantIdentifier, connection); return connection; } public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException { useDb("test", connection); datasourceConnectionProvider.closeConnection(connection); } public boolean supportsAggressiveRelease() { return true; } public void stop() { datasourceConnectionProvider.stop(); } public boolean isUnwrappableAs(Class unwrapType) { return datasourceConnectionProvider.isUnwrappableAs(unwrapType); } public <T> T unwrap(Class<T> unwrapType) { return datasourceConnectionProvider.unwrap(unwrapType); } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { Map settings = serviceRegistry.getService(ConfigurationService.class).getSettings(); DataSource dataSource = (DataSource) settings.get(Environment.DATASOURCE); datasourceConnectionProvider.setDataSource(dataSource); datasourceConnectionProvider.configure(settings); logger.debug("connection provider:{}", datasourceConnectionProvider); } } TenantIdResolver代码 package cutdb.hb; import cutdb.common.model.AppContext; import org.hibernate.Session; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; /** * Created by trq on 2016/6/20. */ public class TenantIdResolver implements CurrentTenantIdentifierResolver { @Override public String resolveCurrentTenantIdentifier() { return AppContext.currentTenantId; } @Override public boolean validateExistingCurrentSessions() { return true; } } 现在问题出来了。我已使用原生sql动态创建数据库,但是如何动态创建表呢? |
|
沙舟狼客
2016-06-22
多租户数据库设计
|
|
沙舟狼客
2016-06-22
关于云架构设计,技术实现,希望大家能进群(487490324)跟我一起讨论。一起学习
|
|
沙舟狼客
2016-06-22
创建数据库的时候增加触发器,自动执行建表脚本。貌似这样最简单。没法放到程序里面调用了
|
|
沙舟狼客
2016-06-22
问题已经解决,代码放在github,有好的建议欢迎一起交流!
地址:https://github.com/ligson/cutdb |
|
LinApex
2016-06-24
有什么用啊?
|
|
zxspopo
2016-06-24
也可以从连接池的角度分析下这个问题。
|
|
沙舟狼客
2016-06-27
LinApex 写道 有什么用啊?
对租户来说: 1.数据想独立 2.可能有定制功能 3.想用更少的资金 对开发者来说: 1.想适应更多的租户需求 2.更少的工作量 3.更快的开发速度 而多租户正好解决了这种需求,由于多租户技术可以让多个租户共用一个应用程序或运算环境,且租户大多不会使用太多运算资源的情况下,对供应商来说多租户技术可以有效的降低环境建置的成本。包含硬件本身的成本,操作系统与相关软件的授权成本都可以因为多租户技术,而由多个租户一起分担。 通过不同的数据管理手段,多租户技术的数据可以用不同的方式进行数据隔离,在供应商的架构设计下,数据的隔离方式也会不同,而良好的数据隔离法可以降低供应商的维护成本(包含设备与人力),而供应商可以在合理的授权范围内取用这些数据分析,以作为改善服务的依据。 多租户架构下所有用户都共用相同的软件环境,因此在软件改版时可以只发布一次,就能在所有租户的环境上生效。 具多租户架构的应用软件虽可客制,但客制难度较高,通常需要平台层的支持与工具的支持,才可降低客制化的复杂度。 |
|
kevincollins
2016-07-01
面向个人租户的,每个id 都有自己独有的数据库和表? 好傻。
面向机构租户,这么干 还行。 |
|
沙舟狼客
2016-07-06
kevincollins 写道 面向个人租户的,每个id 都有自己独有的数据库和表? 好傻。
面向机构租户,这么干 还行。 肯定得面向机构用户,个人用户这么干。不值得 |
相关讨论
相关资源推荐
- 写给开发者的软件架构实战:深入了解多租户软件架构
- multitenancyinhibernate:Hibernate 中的多租户(使用 Hibernate 4.3.7 和 PostgreSql 9.3.1)
- 多租户:Spring Boot + Hibernate + Postgresql的多租户实现Demo
- 多租户--hibernate实现
- springboot-schema-per-tenant:使用SpringBoot和Hibernate实现多租户(每个租户单池模式)的种子
- springboot mysql 多租户_springboot2.3手册:多租户及自动创建数据,这样做
- 多租户架构设计需要考虑解决的几个问题
- 基于Mybatis-Plus的多租户架构下的数据隔离解决方案
- Spring + Hibernate多租户配置
- 多租户数据架构以及hibernate支持(Multi-TenantDataArchitecture)