上一篇写了多表映射,就一口气写完读写分离吧
原理跟多表映射的差不多。
配置读写分离是为了在数据大时读库跟写库分离开来,以加快系统响应速度,减轻数据库压力。
读写原理就是配置多数据源,在调用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>
相关推荐
SSH框架,全称为Struts2、Hibernate和Spring的组合,是Java开发中广泛使用的三大开源框架,它们分别负责Web层、持久层和业务层的管理。这个“java框架ssh框架项目案例”提供了一个完整的示例,帮助开发者了解如何在...
SSH框架,全称为Struts+Spring+Hibernate,是Java Web开发中的一个经典组合,用于构建高效、可扩展的web应用程序。这个压缩包文件包含了使用SSH框架实现的一个功能丰富的网站项目,其中包括了验证码验证、二进制文件...
标题中的“ssh_test.rar_...在实践中,可以尝试修改配置、添加新功能,以加深对SSH框架和读写分离的理解。同时,熟悉相关的开发工具,如Eclipse、IntelliJ IDEA等,以及版本控制系统如Git,也会对你的学习大有裨益。
同时,Hibernate支持缓存机制,可以优化数据库的读写性能。 SSH人事管理系统可能包含以下主要模块: 1. 用户管理:包括用户注册、登录、权限分配等功能,确保只有授权的用户才能访问系统。 2. 员工信息管理:录入...
SSH(Struts2 + Spring + Hibernate)是一种经典的Java Web开发框架组合,用于构建高效、可扩展的企业级应用程序。这个压缩包文件提供了SSH项目所需的多个关键jar包,确保开发者在进行s2sh开发时能避免因缺少依赖而...
SSH三大框架,即Struts、Hibernate和Spring,是Java Web开发中的重要组成部分,它们为开发者提供了构建高效、可维护的应用程序所需的各种工具和功能。这些框架的整合使用,可以极大地提高开发效率,同时降低了项目的...
7. **dom4j.jar**: 这是一个高效的XML处理库,Hibernate使用它来读写XML配置文件。dom4j提供了易于使用的API,使得处理XML文档变得简单。 8. **odmg.jar**: ODMG是对象数据管理组制定的ORM规范,Hibernate实现了这...
SSH系统可能使用CSV、Excel等格式进行数据交换,这通常涉及到文件读写和数据转换。 在实际开发中,SSH科研项目管理系统可能还包括用户认证、权限管理、异常处理、日志记录等多个模块。开发者还需要关注性能优化、...
Hibernate通过DAO与数据库进行交互,完成数据的读写。当操作完成后,Service返回结果给Action,Action再将响应转发给Struts,最终由Struts控制视图的展示,将结果反馈给用户。 SSH框架的优势在于,Struts处理Web...
SSH(Struts2、Spring、Hibernate)是Java Web开发中常用的三大框架,它们各自负责表现层、业务层和持久层的管理。将UEditor整合到SSH框架中,可以实现用户在后台管理系统中方便地编辑和存储富文本内容。 **1. ...
SSH2(Struts2、Spring、Hibernate2)是一种在Java平台上广泛使用的开源企业级开发框架,它整合了三大框架的优势,为构建高效、稳定、可扩展的Web应用提供了强大的支持。在本项目中,SSH2被用来开发一个基于B/S...
7. **读写分离**:在事务配置中,可以设置某些方法为只读事务,如`find002A`方法,这样在执行这些方法时,事务将以只读模式运行,提高了性能。 通过以上步骤,SSH的整合可以实现各个组件之间的协同工作,简化开发...
对于大型项目,可能还需要考虑性能优化,如使用缓存技术、读写分离、分库分表等策略。 综上所述,基于Java SSH的图书在线商店系统是Java Web开发的经典实践,涵盖了Web开发的多个层面,包括用户交互、业务逻辑和...
通过SSH(Struts、Spring、Hibernate)的整合,可以构建出一个完整的MVC架构,使得业务逻辑、控制逻辑和视图分离,每个部分都可以独立开发和测试。而MySQL作为后端数据库,为数据存储提供了可靠的保障。这种技术组合...
标题中的"SPRING+SPRINGMVC+HIBERNATE+MYSQL"是一个经典的Java Web开发技术栈,也被称为SSH框架组合。这个组合是基于Spring框架的扩展,包括Spring的核心容器、Spring MVC作为Web层的解决方案,Hibernate作为持久层...
总结来说,这个网上商城系统利用SSH框架的组合,实现了业务逻辑、控制流和数据访问的分离,提高了代码的可维护性和可扩展性。同时,MySQL数据库提供可靠的数据存储,保证了系统的稳定运行。对于学习Java Web开发的...
6. **测试与优化**:完成上述配置后,进行功能测试,确保数据源切换无误,并对性能进行优化,例如考虑读写分离、负载均衡等策略。 在"ssh双数据源登录.rar"这个压缩包中,可能包含的文件有配置文件(如spring配置...
通过SSH+MYSQL的组合,学生成绩管理系统实现了数据持久化、业务逻辑分离和用户界面的解耦,从而提高了系统的稳定性和可扩展性。开发者可以根据实际需求进行定制,增加新的功能或优化现有功能,以满足不同教育机构的...
DAO使用Hibernate与MySQL交互,完成数据的读写。最后,Action返回结果到视图,JSP页面展示给用户。 7. **学习价值**:这个项目可以帮助学习者了解和掌握SSH整合开发的基本流程,提升对MVC模式的理解,以及如何使用...
【SSH招聘管理系统设计源代码】是一个使用Struts2(S)、Spring(S)和Hibernate(H)这三大Java EE框架构建的应用程序,旨在实现高效、规范化的招聘流程管理。SSH框架是Java Web开发中常见的技术栈,它整合了模型-...