覺得我很密切的多租戶執行的問題,如果這個工程應該幫助了很多人:)
是繼所以這是非常有用的鏈接:Manage Connection Pooling in multi-tenant web app with Spring, Hibernate and C3P0
我的問題是,在我的類,它實現 - MultiTenantConnectionProvider休眠模式,injectservices
我沒有得到一個句柄javax.sql.Datasource取得
這裏是我的全碼:
彈簧應用程序上下文:
<bean id="testService" class="com.mkyong.common.service.TestServiceImpl" lazy-init="true">
<property name="testDao" ref="testDao" />
</bean>
<bean id="testDao" class="com.mkyong.common.dao.TestDaoImpl" lazy-init="true">
<!-- Injecting Standard Session Factory -->
<property name="sessionFactory" ref="sessionFactoryWorking" />
</bean>
<!-- this seems to work -->
<jee:jndi-lookup id="dataSource" jndi-name="MYSQLDS"/>
<!-- SessionFactories -->
<!-- Standard Session Factory -->
<bean id="sessionFactoryWorking" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:local.JADE.PIT.hibernate.cfg.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManagerWorking" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="autodetectDataSource" value="false" />
<property name="sessionFactory" ref="sessionFactoryWorking" />
</bean>
在文件local.JADE.PIT.hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property>
<property name="multiTenancy">SCHEMA</property>
<property name="multi_tenant_connection_provider">com.mkyong.common.provider.MySQLMultiTenantConnectionProviderImpl</property>
&globalpit;
</session-factory>
這裏是我的MySQLMultiTenantConnectionProviderImpl
package com.mkyong.common.provider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.cfg.Environment;
import java.util.Map;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
public class MySQLMultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider,ServiceRegistryAwareService{
private DataSource lazyDatasource;;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
System.out.println(" satish ********************** " + Environment.DATASOURCE);
System.out.println(" satish ********************** " + lSettings.get(Environment.DATASOURCE));
lazyDatasource = (DataSource) lSettings.get(Environment.DATASOURCE);
}
@Override
public boolean supportsAggressiveRelease() {
System.out.println("<<<<<<< satish supportsAggressiveRelease >>>>>>>>>");
/** this method must be overriden **/
return false;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection){
/** this method must be overriden **/
System.out.println("<<<<<<< satish releaseConnection 1 >>>>>>>>>");
try {
this.releaseAnyConnection(connection);
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
System.out.println("<<<<<<< satish releaseAnyConnection 2 >>>>>>>>>");
/** this method must be overriden **/
connection.close();
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
System.out.println("<<<<<<< satish getConnection 1 >>>>>>>>>");
final Connection connection = getAnyConnection();
System.out.println("<<<<<<< satish getConnection 2 >>>>>>>>>");
try {
/** this is the place where we can change our schema based on identifier **/
connection.createStatement().execute("USE " + tenantIdentifier);
}catch (SQLException e) {
e.printStackTrace();
throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
}
return connection;
}
@Override
public Connection getAnyConnection() throws SQLException {
/** this method is getting called first **/
System.out.println("<<<<<<< satish getAnyConnection >>>>>>>>>");
return lazyDatasource.getConnection();
}
@SuppressWarnings("unchecked")
@Override
public <T> T unwrap(Class<T> unwrapType) {
if (isUnwrappableAs(unwrapType)) {
return (T) this;
}else {
throw new UnknownUnwrapTypeException(unwrapType);
}
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals(unwrapType) || MultiTenantConnectionProvider.class.equals(unwrapType) || MySQLMultiTenantConnectionProviderImpl.class.isAssignableFrom(unwrapType);
}
}
這裏是我的DAO:
public class TestDaoImpl{
/** schema choice which comes from UI/http - which is outside the scope of this example **/
private String schema = null;
/** this is the injected way which works **/
private SessionFactory sessionFactory;
public final void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void setSchema(String schema) {
this.schema = schema;
}
public Session getCurrentSession() {
Session session = null;
try {
**/** this is where we are getting a connection based on client/tenant **/**
session = getSessionFactory().withOptions().tenantIdentifier(schema).openSession();
} catch (HibernateException e) {
e.printStackTrace();
System.out.println("<<<<<< inside exception while getting session from sf >>>>>");
session = getSessionFactory().openSession();
}
return session;
}
@SuppressWarnings("unchecked")
public List<Person> list() {
Session session = getCurrentSession();
List<Person> personList = session.createQuery("from Person").list();
session.close();
return personList;
}
}
所以發生的是,該方法 - injectServices - 它是越來越援引
然而,數據源是空在下面一行:
lSettings .get(Environment.DATASOURCE)
如果我在我的cfg.xml文件中設置數據源名稱 -
MYSQLDS
然後我得到的返回值「MYSQLDS」 - 但它是一個字符串 - 所以在試圖投和javax.sql.DataSource
多幾個音符就那麼失敗:
通過文字讀取休眠文件詞,因爲這是非常非常重要的 - 他們是在給窮人的例子 - 但文檔需要一個完全新的和增強的意義 - 如果你仔細閱讀:) - http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
注 - 我的數據源是一個weblogic jndi提供的datasour CE
感謝
編輯1 2014年12月29日11:35 AM IST
如前所述由M Deinum - 問題是,我沒有有線我的數據源
現在確實是工作 - 上述更新的代碼 - 這樣這應該工作,並幫助他人呢!
重申發佈的步驟的執行順序:
在我們的UI層,我們都知道它的客戶端在訪問應用
我們通過這個客戶端/租戶信息到DAO層
的DAO被注入SessionFactory的是在Spring
配置在DAO - 我們基於租戶獲取會話 - 的getCurrentSession()
這是非常重要的是得到基於租戶conenction
會話=了getSessionFactory()withOptions()tenantIdentifier(模式).openSession(。 );
現在,一旦我們有了會話,我們撥打電話:
List<Person> personList = session.createQuery("from Person").list();
此時類MySQLMultiTenantConnectionProviderImpl被調用
public Connection getConnection(String tenantIdentifier) throws SQLException {
這的下面方法的地方, mojo發生/我們預計寫 - 你改變架構
在我的情況我使用的MySQL,所以語法會根據t他數據庫中正在使用:
connection.createStatement().execute("USE " + tenantIdentifier);
完蛋了 - 多租戶(獨立的模式)的這種做法現在工作
還要說明一點 - 我沒有使用 - CurrentTenantIdentifierResolver
Hibernate文檔:(我不明白第一下面的段落 - 但是第二段似乎表明,這個類是沒有必要的,如果指定從SessionFactory的承包者標識符) - 這是我在做什麼,所以我沒有定義類 - CurrentTenantIdentifierResolver
有2種情形w ^這裏使用CurrentTenantIdentifierResolver:
The first situation is when the application is using the
org.hibernate.context.spi.CurrentSessionContext feature in conjunction with multi-tenancy.
In the case of the current-session feature, Hibernate will need to open a session if it cannot
find an existing one in scope. However, when a session is opened in a multi-tenant environment
the tenant identifier has to be specified. This is where the CurrentTenantIdentifierResolver
comes into play; Hibernate will consult the implementation you provide to determine the tenant
identifier to use when opening the session. In this case, it is required that a
CurrentTenantIdentifierResolver be supplied.
The other situation is when you do not want to have to explicitly specify the tenant identifier
all the time as we saw in Example 16.1, 「Specifying tenant identifier from SessionFactory」.
If a CurrentTenantIdentifierResolver has been specified, Hibernate will use it to determine
the default tenant identifier to use when opening the session.
再次非常感謝到M Deinum爲輕推我在這個方向及幫助
感謝
對於初學者來說,你的數據源不會被注入到會話工廠,它只會被查找,在忘記之後,你應該在配置中添加' '。 –
@ m-deinum - 感謝您投入 - 我實際上是要爲您寫評論 - 是的 - 您的建議似乎有效 - 我會做更多的測試並回寫所做的任何更改 - 非常感謝您的幫助:) - 你可以發佈你的答案,以便它可以被接受 - 不能說我多麼感激! –