SSH架构操作多数据库
来源:互联网 发布:淘宝扫码付款被骗 编辑:程序博客网 时间:2024/05/18 10:33
SSH架构操作多数据库
注意事项
建议:不要多个系统同时对一个数据库进行增删改操作,但是可以有多个系统同时查询同一个数据库。
原理分析
绝大多数情况下,我们使用SSH(Struts+spring+hibernate)架构只需要操作一个数据库,操作数据库原理为:
在spring的配置文件中,配置一个数据源DataSource,数据源中配置一个数据库连接池;
在spring的配置文件中,配置一个会话工厂SessionFactory,再将数据源DataSource关联到会话工厂sessionFactory上;
在持久层(Dao层),使用spring注入SessionFactory对象,使用SessionFactory创建Session,在进行数据库操作。
其中,Spring中DataSource和sessionFactory的配置如下:
<!-- 数据源 -->
<beanid="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass"value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"value="jdbc:mysql:///**数据库名称**?characterEncoding=utf8" />
<property name="user"value="A_username"/>
<propertyname="password"value="A_password"/>
</bean>
<!-- 配置SessionFactory(与Hibernate整合) -->
<beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 指定Hibernate配置文件路径 -->
<propertyname="configLocation"value="classpath:hibernate.cfg.xml"></property>
<!-- 指定数据库连接池 -->
<propertyname="dataSource"ref="dataSource"></property>
</bean>
由上述所说,我们可以简单的表示为:
这是spring提供的操作单个数据库的方法,spring同时还提供了操作多数据库的方式(此处以两个数据库为例),其原理为:
此处我引入一个动态数据源的概念,其实就是动态的切换数据源,先看一下动态数据源的用法,其实原理也就不言而喻了。
<!-- A数据源 -->
<beanid="dataSourceA"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass"value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"value="jdbc:mysql:///**数据库名称**?characterEncoding=utf8" />
<property name="user"value="A_username"/>
<propertyname="password"value="A_password"/>
</bean>
<!-- B数据源 -->
<beanid="dataSourceB"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass"value=" com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql:///**数据库名称**?characterEncoding=utf8"/>
<propertyname="user"value="B_username"/>
<propertyname="password"value="B_password"/>
</bean>
<!-- 动态数据源 -->
<beanid="dataSource"class="a.core.DynamicDataSource">
<propertyname="targetDataSources">
<mapkey-type="java.lang.String">
<entrykey="dataSourceA"value-ref="dataSourceA"/>
<entrykey="dataSourceB"value-ref="dataSourceB"/>
</map>
</property>
<propertyname="defaultTargetDataSource"ref="dataSourceA"/>
</bean>
<!-- 配置SessionFactory(与Hibernate整合) -->
<beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 指定Hibernate配置文件路径 -->
<propertyname="configLocation"value="classpath:hibernate.cfg.xml"></property>
<!-- 指定数据库连接池 -->
<propertyname="dataSource"ref="dataSource"></property>
</bean>
通过对比,我们可以看出:其实从本质上来说,动态数据源也是一个数据源,区别在与每次访问的数据源不同。因此,当决定了使用哪个数据源后,其他工作原理与上面单个数据库的原理一样。现在的问题就剩下了如何确定数据源以及什么时候确定数据源两个问题了。我们先来研究一下什么时候确定数据源。
首先,我们使用的是spring配合hibernate的架构,在使用hibernate作为持久层框架时,为避免出现懒加载异常,在web.xml中,都会配置OpenSessionInViewFilter——在表现层开启session的过滤器,保障在表现层调用时,不会出现异常。
我们如果配置了这一项,也就意味着项目在请求到达表现层之前就已经开启了session,而创建session需要使用sessionFactory创建,sessionFactory又依赖DataSource,因此dynamicDataSource使用哪个DataSource,应该在执行过滤器OpenSessionInViewFilter之前,就已经确定了。
因此,我的解决方案是:在web.xml中,过滤器OpenSessionInViewFilter之前配置一个DataSourceFIlter过滤器,用来确定动态数据源中使用哪个数据源。
如何确定使用哪个DataSource的步骤:
1. 在web.xml中,配置一个过滤器在OpenSessionInViewFilter;
2. 新建一个类DynamicDataSource,继承AbstractRoutingDataSource,重写determineCurrentLookupKey方法,用于决定使用哪个数据源DataSource;
3. Copy操作动态数据源的工具类DatabaseContextHolder的代码;
4. 有了2和3中的两个类,只需要一行代码,即可设置数据源:DatabaseContextHolder.setCustomerType("dataSourceB");
5. 在过滤器中根据路径判断使用哪个数据源
6. 具体代码如下:
代码展示
Web.xml中的配置:
<filter>
<filter-name>DynamicDataSourceFilter</filter-name>
<filter-class>a.core.DynamicDataSourceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>DynamicDataSourceFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
过滤器a.core.DynamicDataSourceFilter的代码:
package a.core;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
public class DynamicDataSourceFilterimplements Filter {
@Override
publicvoid destroy() {
}
@Override
publicvoid doFilter(ServletRequest req, ServletResponse resp,
FilterChainfilterChain) throws IOException, ServletException {
HttpServletRequestrequest = (HttpServletRequest) req;
Stringuri = request.getRequestURI();
System.out.println(uri);
if(uri.contains("person")){
DatabaseContextHolder.setCustomerType("dataSourceB");
// DatabaseContextHolder是一个工具类,下附代码
System.out.println("B");
}else{
DatabaseContextHolder.setCustomerType("dataSourceA");
System.out.println("A");
}
filterChain.doFilter(req,resp);
}
@Override
publicvoid init(FilterConfig arg0) throws ServletException {
}
}
动态数据源DynamicDataSource的代码:
package a.core;
importjava.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extendsAbstractRoutingDataSource {
@Override
protectedObject determineCurrentLookupKey() {
returnDatabaseContextHolder.getCustomerType();
}
@Override
publicLogger getParentLogger() throws SQLFeatureNotSupportedException {
returnnull;
}
}
操作动态数据源的工具类DatabaseContextHolder的代码:
package a.core;
public classDatabaseContextHolder{
private static finalThreadLocal<String>contextHolder = newThreadLocal<String>();
public static void setCustomerType(StringcustomerType) {
contextHolder.set(customerType);
}
public static StringgetCustomerType() {
returncontextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
Spring的配置文件
<!-- A数据源 -->
<beanid="dataSourceA"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass"value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"value="jdbc:mysql:///**数据库名称**?characterEncoding=utf8" />
<property name="user"value="A_username"/>
<propertyname="password"value="A_password"/>
</bean>
<!-- B数据源 -->
<beanid="dataSourceB"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass"value=" com.mysql.jdbc.Driver"/>
<propertyname="jdbcUrl"value="jdbc:mysql:///**数据库名称**?characterEncoding=utf8"/>
<propertyname="user"value="B_username"/>
<propertyname="password"value="B_password"/>
</bean>
<!-- 动态数据源 -->
<beanid="dataSource"class="a.core.DynamicDataSource">
<propertyname="targetDataSources">
<mapkey-type="java.lang.String">
<entrykey="dataSourceA"value-ref="dataSourceA"/>
<entrykey="dataSourceB"value-ref="dataSourceB"/>
</map>
</property>
<propertyname="defaultTargetDataSource"ref="dataSourceA"/>
</bean>
<!-- 配置SessionFactory(与Hibernate整合) -->
<beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 指定Hibernate配置文件路径 -->
<propertyname="configLocation"value="classpath:hibernate.cfg.xml"></property>
<!-- 指定数据库连接池 -->
<propertyname="dataSource"ref="dataSource"></property>
</bean>
- SSH架构操作多数据库
- SSH多数据库连接
- 多数据库操作
- SSH+连接池配置多数据库
- SSH框架操作多数据库 (补16年12月)
- drupal7 多数据库操作
- EJB操作多数据库
- ThinkPHP多数据库操作
- yii2 多数据库操作
- laravel 多数据库操作
- SSH 多数据源连接
- SSH多数据源配置
- Yii: 多数据库配置和操作
- QT SQLite 多数据库操作大全
- QT SQLite 多数据库操作大全
- tp5中多数据库操作
- 三层架构下的多数据库连接
- SSH项目多数据源的配置
- 策略设计模式
- last_insert_id()函数使用的注意事项 mysql
- mysql迁移数据文件
- TYPESDK手游聚合SDK客户端设计思路与架构之二:安卓平台统一化接口结构及思路
- 3D游戏开发之在UE4中创建非玩家角色(NPC)
- SSH架构操作多数据库
- 致CSDN的感谢信
- TYPESDK手游聚合SDK客户端设计思路与架构之三:iOS平台统一化接口结构及思路
- mysql主从架构的复制原理及配置详解
- Leetcode 2. Add Two Numbers
- 单词接龙-洛谷 1019
- struts2保存表单后,进入列表页用redirectAction
- [001-Cortex_M3-GCC汇编] 第一个点灯程序
- 鼠标放上去显示/隐藏效果