ssh,hibernate 读写分离
程序员文章站
2024-03-26 09:40:23
...
上一篇写了多表映射,就一口气写完读写分离吧
原理跟多表映射的差不多。
配置读写分离是为了在数据大时读库跟写库分离开来,以加快系统响应速度,减轻数据库压力。
读写原理就是配置多数据源,在调用service层时用spring的aop把方法都拦下来,然后根据方法名称如find开头,get开头这样的就设置读数据源,其它就设置写数据源。
在注入dao层时的sessionFactory就要给sessionFactory注入路由数据源,而不是具体一个数据源了,这样才可以动态的设置数据源。
主要就是这个路由数据源DynamicDataSource继承AbstractRoutingDataSource,重写码 determineCurrentLookupKey,动态lookup数据源
上代码吧:
数据源选择类
/**
* 数据源选择类
* @author miraclerz
*/
import org.springframework.util.Assert;
public class DataSourceSwitcher {
@SuppressWarnings("rawtypes")
private static final ThreadLocal contextHolder = new ThreadLocal();
@SuppressWarnings("unchecked")
public static void setDataSource(String dataSource) {
Assert.notNull(dataSource, "dataSource cannot be null");
contextHolder.set(dataSource);
}
public static void setMaster(){
clearDataSource();
// setDataSource("master");
}
public static void setSlave() {
setDataSource("slave");
}
public static String getDataSource() {
return (String) contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
数据源动态切换类
/**
* 数据源动态切换类
* @author miraclerz
*/
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
/*System.out.println("dataSource:"+DataSourceSwitcher.getDataSource());*/
return DataSourceSwitcher.getDataSource();
}
}
AOP切面类
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import sy.datasource.DataSourceSwitcher;
/**
* AOP切面类
* @author miraclerz
*/
public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
// service方法执行之前被调用
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("切入点: " + target.getClass().getName() + "类中" + method.getName() + "方法");
if(method.getName().startsWith("get")
|| method.getName().startsWith("find")
|| method.getName().startsWith("count")){
/* System.out.println("切换到读: slave");*/
DataSourceSwitcher.setSlave();
}
else {
/* System.out.println("切换到主写: master");*/
DataSourceSwitcher.setMaster();
}
System.out.println("使用数据库:"+DataSourceSwitcher.getDataSource());
}
// service方法执行完之后被调用
public void afterReturning(Object arg0, Method method, Object[] args, Object target) throws Throwable {
}
// 抛出Exception之后被调用
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
DataSourceSwitcher.setMaster();
System.out.println("出现异常,切换到: master");
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--读写分离配置 -->
<!-- 加载properties配置文件 -->
<!-- <bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:readWrite/jdbc.properties</value>
</list>
</property>
</bean> -->
<bean id="parentDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${master.jdbc.driverClassName}" />
<property name="url" value="${master.jdbc.url}" />
<property name="username" value="${master.jdbc.username}" />
<property name="password" value="${master.jdbc.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="mergeStat" /> -->
<property name="filters" value="stat" />
</bean>
<!-- 主数据源 -->
<bean id="masterDataSource" parent="parentDataSource">
<property name="driverClassName" value="${master.jdbc.driverClassName}" />
<property name="url" value="${master.jdbc.url}" />
<property name="username" value="${master.jdbc.username}" />
<property name="password" value="${master.jdbc.password}" />
<property name="validationQuery" value="${master.hibernate.validationQuery}" />
</bean>
<!-- 从数据源 读-->
<bean id="slaveDataSource" parent="parentDataSource">
<property name="driverClassName" value="${slave.jdbc.driverClassName}" />
<property name="url" value="${slave.jdbc.url}" />
<property name="username" value="${slave.jdbc.username}" />
<property name="password" value="${slave.jdbc.password}" />
<property name="validationQuery" value="${slave.hibernate.validationQuery}" />
</bean>
<!--dynamicDataSource 是用的数据源,包括了读写数据源 -->
<bean id="dynamicDataSource" class="sy.datasource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="master" value-ref="masterDataSource" />
<entry key="slave" value-ref="slaveDataSource" />
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource" />
</bean>
<!-- 配置sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${read_write_hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${read_write_hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${read_write_hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${read_write_hibernate.format_sql}</prop>
<prop key="hibernate.use_sql_comments">${read_write_hibernate.use_sql_comments}</prop>
</props>
</property>
<!-- 自动扫描注解方式配置的hibernate类文件 -->
<property name="packagesToScan">
<list>
<value>sy.model.base</value>
</list>
</property>
</bean>
<!-- 切换数据源 -->
<bean id="dataSourceAdvice" class="sy.aop.DataSourceAdvice" />
<aop:config>
<aop:advisor
pointcut="(execution(* sy.service.base..*Impl.*(..)))"
advice-ref="dataSourceAdvice" />
</aop:config>
<!-- 配置事务管理器 -->
<bean id="read_write_transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 拦截器方式配置事物 -->
<tx:advice id="read_write_txAdvice" transaction-manager="read_write_transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="saveOrUpdate*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="grant*" propagation="REQUIRED" />
<tx:method name="init*" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 第一个*代表所有的返回值类型;第二个*代表所有的类;第三个*代表类所有方法;..代表子或者孙子包;最后一个..代表所有的参数 -->
<aop:pointcut id="read_write_transactionPointcut" expression="(execution(* sy.service.base..*Impl.*(..)))" />
<aop:advisor pointcut-ref="read_write_transactionPointcut" advice-ref="read_write_txAdvice" />
</aop:config>
</beans>
上一篇: ca65a_c++_类的成员函数_txwtech_this指针
下一篇: python的高阶函数
推荐阅读
-
CentOS6中MySql5.6数据库主从复制/读写分离(二)
-
ssh,hibernate 读写分离
-
DM8 datawatch4.0读写分离集群部署
-
MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践 博客分类: 数据库集群
-
hibernate 博客分类: ssh2 HibernateHSQLDBSQLOracleMySQL
-
mysql 读写分离方法 博客分类: mysql javamysql
-
Linux MySQL数据库集群实战 读写分离
-
SSH有关理解 博客分类: SSH hibernate设计模式springstruts
-
《Centos7——MYSQL主从复制+读写分离》
-
运维之道 | Mysql主从复制+mycat读写分离