`
miraclerz
  • 浏览: 96811 次
社区版块
存档分类
最新评论

ssh,hibernate 读写分离

阅读更多

   上一篇写了多表映射,就一口气写完读写分离吧

   原理跟多表映射的差不多。

   配置读写分离是为了在数据大时读库跟写库分离开来,以加快系统响应速度,减轻数据库压力。

  读写原理就是配置多数据源,在调用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>

 

 

0
0
分享到:
评论

相关推荐

    java框架ssh框架项目案例

    ssh框架项目案例,主要是Struts2+Hibernate+Spring框架集合,用于学习使用。

    springboot+shardingjdbc+hikari+jpa+KingbaseES V8R6

    1:多租户系统集成 2:集成shardingjdbc分库分表 3:集成shardingjdbc读写分离 4:集成人大金仓数据库 5:重写了JPA-saveandflush方法 6:修复了JPA更新数据为null的问题 7:解压后导入idea,创建数据库即可运行测试

    低清版 大型门户网站是这样炼成的.pdf

    (Struts 2+Spring 2+Hibernate 3).pdf(完整版) 网上有高清版350M的。可以去下 http://115.com/file/be5gwid8 请于下载后 24H 内及时删除!请抱着学习的态度下载此资料。 总共900多页!!!!!!! 第1篇 ...

    java开源包1

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包11

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包2

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包3

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包6

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包5

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包10

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包4

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包8

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包7

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包9

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    java开源包101

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    Java资源包01

    支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL...

    JAVA上百实例源码以及开源项目

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    JAVA上百实例源码以及开源项目源代码

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    java源码包---java 源码 大量 实例

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

Global site tag (gtag.js) - Google Analytics