我目前正在尝试使用单独的Schema方法为多租户设置Hibernate。
经过大约2天的研究并浏览了几乎所有我可以通过Google找到的资源,我开始感到非常沮丧。
基本上,我试图遵循Hibernate开发指南http://docs.jboss.org/hibernate/orm/4.1/devguide/zh-
CN/html_single/#d5e4691中
提供的指南,
但是很遗憾,我找不到ConnectionProviderUtils来建立ConnectionProvider。目前,我正在尝试找出2点:
为什么从未调用过我的MSSQLMultiTenantConnectionProvider的configure(Properties props)方法。根据我从其他不同ConnectionProvider实现的来源和描述中所解释的内容,我假设将调用此方法来初始化ConnectionProvider。
由于我无法使用configure(Properties props),因此尝试了其他方法来以某种方式获取应用程序Context和hibernate.cfg.xml中指定的hibernate属性和数据源。(就像将数据源直接注入到ConnectionProvider中一样)
解决此问题的可能方法的任何指针(方法,类,教程)
因此,这是实现的相关部分:
数据源和Hibernate.cfg.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://<host>:<port>;databaseName=<DbName>;" />
<property name="username" value=<username> />
<property name="password" value=<password> />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- property name="dataSource" ref="dataSource" /-->
<property name="annotatedClasses">
<list>
<value>c.h.utils.hibernate.User</value>
<value>c.h.utils.hibernate.Role</value>
<value>c.h.utils.hibernate.Tenant</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.show_sql=true
hibernate.multiTenancy=SCHEMA
hibernate.tenant_identifier_resolver=c.h.utils.hibernate.CurrentTenantIdentifierResolver
hibernate.multi_tenant_connection_provider=c.h.utils.hibernate.MSSQLMultiTenantConnectionProviderImpl
</value>
</property>
</bean>
MSSQLMultiTenantConnectionProviderImpl:
package c.hoell.utils.hibernate;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MSSQLMultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {
private static final long serialVersionUID = 8074002161278796379L;
@Autowired
private DataSource dataSource;
public void configure(Properties props) throws HibernateException {
}
@Override
public Connection getAnyConnection() throws SQLException {
Properties properties = getConnectionProperties(); //method which sets the hibernate properties
DriverManagerConnectionProviderImpl defaultProvider = new DriverManagerConnectionProviderImpl();
defaultProvider.configure(properties);
Connection con = defaultProvider.getConnection();
ResultSet rs = con.createStatement().executeQuery("SELECT * FROM [schema].table");
rs.close(); //the statement and sql is just to test the connection
return defaultProvider.getConnection();
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
<--not sure how to implement this-->
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection){
try {
this.releaseAnyConnection(connection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProvider.class.equals( unwrapType ) || MSSQLMultiTenantConnectionProviderImpl.class.isAssignableFrom( unwrapType );
}
@SuppressWarnings("unchecked")
@Override
public <T> T unwrap(Class<T> unwrapType) {
if ( isUnwrappableAs( unwrapType ) ) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
现在,我发现有两种可能的方法可以从配置文件中获取所需的配置。使configure()方法运行或以某种方式使注入DataSource成为可能。我想第一个会是更好的方法。
值得一提的是,我只有一个租户才能运行并运行Hibernate(这意味着无需使用MultiTenantConnectionProvider,而是使用Hibernate使用的标准ConnectionProvider)。
非常感谢正在阅读这篇文章的任何人。期待答案。
最好的祝福
我对此进行了一些尝试,并将连接细节硬编码到我的MultiTenantConnectionProvider中(更新了上面的代码)。就MultiTenantConnectionProvider而言,这工作正常。但这仍然不能解决我的问题。现在我的应用程序无法初始化
事务管理器 :
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
这是 异常stacktrace 的顶部:
造成原因:org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:264)上的org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:264)上的org.springframework.orm.hibernate4.SessionFactoryUtils.getDataSource(SessionFactoryUtils.java:101)处的java.lang.NullPointerException
.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
我在调试模式下跟踪了此问题,发现问题是我的SessionFactory无法以某种方式掌握数据源。(无论是否在hibernate.cfg.xml中指定DataSource都没有区别),但是在初始化TransactionManager时,它将尝试从SessionFactory获取DataSource并因此失败,并出现NullPointerException。有没有人暗示hibernate内部工作的哪一点失败了?在我看到的所有文档和帖子中,都没有迹象表明我需要处理将DataSource注入SessionFactory的问题。现在,我只是想尝试找出如何将DataSource放入所需位置或如何更改初始化流程。如果有人有更好的主意,我会很高兴。
编辑:现在也将其发布在Hibernate论坛中:
所以我设法通过将TransactionManager中的autodetectDataSource属性设置为false来解决此问题:
<property name="autodetectDataSource" value="false"/>
我从下面的帖子http://forum.springsource.org/showthread.php?123478-SessionFactory-
configured-for-multi-tenancy-but-no-tenant-identifier-
specified中得到了这个提示。不幸的是,我现在正停留在这个问题上。^^“但这是另一个主题的问题。(编辑:原来这只是早期测试中的错误配置+一个旧的依赖项)
至于这个主题,问题仍然是我想要以某种方式能够重用DataSource,以便Hibernate避免必须在两个地方配置DataSource,无论如何我已经在配置中已经使用Spring
Security了。因此问题仍然存在,即如何在我的MultiTenantConnectionProvider中集成数据源的使用。有谁知道在哪里可以找到任何提示吗?
总结一下,这就是我的以下内容。我使用一个简单的CurrentTenantIdentifierResolver。并且没有尝试将数据源从其他地方注入到我的MultiTenantConnectionProviderImpl中,而是在ConnectionProvider中创建了DataSource(c3p0
ComboPooledDatasource),并仅使用了由我的ConnectionProvider提供的连接。因此,我消除了多余的DataSource。为了使DataSource的属性易于配置,我选择从属性文件中获取配置数据。
CurrentTenantIdentifierResolverImpl:
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
/**
* The method returns the RequestServerName as tenantidentifier.
* If no FacesContext is available null is returned.
*
* @return String tenantIdentifier
*/
@Override
public String resolveCurrentTenantIdentifier() {
if (FacesContext.getCurrentInstance() != null){
return FacesContext.getCurrentInstance().getExternalContext().getRequestServerName();
} else {
return null;
}
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
MultiTenantConnectionProviderImpl:
请注意,PropertyUtil只是一个简单的本地帮助程序类,用于获取我的属性。由于没有什么特别之处,因此我不会将其包括在内以免弄乱答案。
public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {
private static final long serialVersionUID = 8074002161278796379L;
private static Logger log = LoggerFactory.getLogger(MultiTenantConnectionProviderImpl.class );
private ComboPooledDataSource cpds;
private Properties properties;
/**
*
* Constructor. Initializes the ComboPooledDataSource based on the config.properties.
*
* @throws PropertyVetoException
*/
public MultiTenantConnectionProviderImpl() throws PropertyVetoException {
log.info("Initializing Connection Pool!");
properties = new Properties();
try {
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) {
throw new RuntimeException(e);
}
cpds = new ComboPooledDataSource("Example");
cpds.setDriverClass(properties.getProperty("jdbc.driver"));
cpds.setJdbcUrl(properties.getProperty("jdbc.url"));
cpds.setUser(properties.getProperty("jdbc.user"));
cpds.setPassword(PropertyUtil.getCredential("jdbc.password"));
log.info("Connection Pool initialised!");
}
@Override
public Connection getAnyConnection() throws SQLException {
log.debug("Get Default Connection:::Number of connections (max: busy - idle): {} : {} - {}",new int[]{cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize()){
log.warn("Maximum number of connections opened");
}
if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize() && cpds.getNumIdleConnectionsAllUsers()==0){
log.error("Connection pool empty!");
}
return cpds.getConnection();
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
log.debug("Get {} Connection:::Number of connections (max: busy - idle): {} : {} - {}",new Object[]{tenantIdentifier, cpds.getMaxPoolSize(),cpds.getNumBusyConnectionsAllUsers(),cpds.getNumIdleConnectionsAllUsers()});
if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize()){
log.warn("Maximum number of connections opened");
}
if (cpds.getNumConnectionsAllUsers() == cpds.getMaxPoolSize() && cpds.getNumIdleConnectionsAllUsers()==0){
log.error("Connection pool empty!");
}
return cpds.getConnection(tenantIdentifier, PropertyUtil.getCredential(tenantIdentifier));
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection){
try {
this.releaseAnyConnection(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@SuppressWarnings("rawtypes")
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProvider.class.equals( unwrapType ) || MultiTenantConnectionProviderImpl.class.isAssignableFrom( unwrapType );
}
@SuppressWarnings("unchecked")
@Override
public <T> T unwrap(Class<T> unwrapType) {
if ( isUnwrappableAs( unwrapType ) ) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
}
特定于 c3p0的 配置来自 c3p0-config.xml :
<c3p0-config>
<named-config name="Example">
<property name="acquireIncrement">3</property>
<property name="preferredTestQuery">SELECT 1</property>
<property name="checkoutTimeout">2000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">1</property>
<property name="maxIdleTime">18000</property>
<property name="maxPoolSize">30</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">50</property>
<property name="testConnectionOnCheckin">true</property>
</named-config>
</c3p0-config>
db特定的属性由 config.properties 文件提供:
jdbc.url=<serverUrl>
jdbc.driver=<driverClass>
jdbc.dbName=<dBname>
jdbc.dbowner=<dbo>
jdbc.username=<user>
jdbc.password=<password>
hibernate.dialect=<hibernateDialect>
hibernate.debug=false
从另一个文件以类似的方式获取凭据。
任何提供改进的反馈意见表示赞赏。
我找不到Rails,让travis去工作。当测试开始运行时,仍然会出现数据库连接错误。 和 我必须使用单独的数据库配置。 知道我做错了什么吗?按照http://about.travis-ci.org/docs/user/database-setup/中的文档,除了我必须将数据库配置复制到正确的位置之外。
问题内容: 我正在尝试在我的React项目上使用Airbnb的Javascript标准设置linting,它使用webpack。 根据评论更新了最新软件包。 我的webpack配置中也有一个预加载器设置 并进行了以下设置以运行脚本 我也有一个包含以下内容的文件 这给了我以下错误: 如果删除我认为可能有冲突的文件,则会出现以下错误: 随后出现npm错误,该错误导致任务退出。 任何帮助,将不胜感激!
问题内容: 我正在尝试使用jQuery访问Google文档。这是我到目前为止的内容: 如果将设置为,则不允许我设置标头(来自使用jQuery的跨域Ajax请求)。如果遗漏了,我将无法提出跨域请求。如果使用,则无法传递任何标题… 发出跨域ajax请求时(在jQuery中),有什么方法可以定义自定义标头? 问题答案: 这是不可能的。 JSONP请求的工作原理是创建一个元素,并将其属性设置为请求URL。
问题内容: 当您想使用Javascript更改HTML时,如何知道何时使用以下任一方法? 问题答案: 设置通常用于输入/表单元素。通常用于div,span,td和类似元素。
问题内容: 我的环境 Java 5 Spring2.5.5 DBCP数据源 (org.apache.commons.dbcp.BasicDataSource) 的MySQL 类似职位 使用Spring JDBC Oracle设置会话时区 链接 http://www.mysqlfaqs.net/mysql-faqs/General-Questions/How-to-manage-Time-Zone-
问题内容: 我有多个IP可以上网。我正在请求选择界面。在这种情况下,我应该如何设置标题? 通常,头是以这种方式设置的: 但是无法弄清楚如何将它们设置为我的代码。 我想它们必须放在或中的某个位置。但是到底如何呢? 我的完整代码: 问题答案: 创建一个请求: 设置标题: 使用问题中配置的方式运行请求: 按照问题所示处理响应。