数据库主备
在高并发的环境下数据库常常会进行高可用的拓展,例如分库分表,读写分离,集群,主备,主备复制,当然也会暴露很多的问题:数据迁移,数据一致性,单点故障等等问题。
(当然上述的内容都要根据公司内部的业务场景、数据量、访问量、并发量、高可用的要求)
这些大部分的操作都不是开发人员操心的,我们操心的是如何在应用层的读写分离(驱动层应该会更好吧),多数据源主备切换等等,此次分享的就是一个在Mybaits+spring整合的情况下多数据源切换和读写分离的案例
项目说明
1.读写分离:写操作进入到主库,读操作进入到备库集。
2.多数据源:采用一主多从的数据源配置 ,根据操作切换数据源
3.使用java项目搭建
注意:读写分离的情况下,主备数据同步依靠于本身提供的数据库同步复制功能
项目
- 加入项目需要的jar包
- 项目配置文件
- 项目
2.1 applicationContext.xml (头尾省去)
<context:annotation-config />
<!-- <context:component-scan base-package="dao" /> -->
<aop:aspectj-autoproxy/>
<!-- ibatis3 工厂类 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
<bean id="dynamicSqlSessionTemplate" class="datasource.DynamicSqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" ref="sqlSessionTemplate" />
</bean>
<!-- mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionTemplate" ref="dynamicSqlSessionTemplate"></property>
<!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号隔开 com.yuhiwy.SysManager.dao-->
<property name="basePackage" value="dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
2.2 applicationContext-tx.xml
<!-- 定义单个jdbc数据源的事务管理器 -->
<bean id="transactionManager"
class="datasource.DynamicDataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 以 @Transactional 标注来定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="Exception" />
<tx:method name="proc*" propagation="REQUIRED" read-only="false"
rollback-for="Exception" />
<tx:method name="select*" read-only="true" />
<tx:method name="*" read-only="false" />
<!-- <tx:method name="*" read-only="true" /> -->
</tx:attributes>
</tx:advice>
<aop:aspectj-autoproxy/>
<!-- 那些类的哪些方法参与事务 -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution(* dao..*(..))" />
<aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice" />
</aop:config>
2.3 application-dataSource.xml
<!-- C3P0连接池配置 -->
<bean id="master" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 基本属性 url、user、password -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="20"/>
<property name="minIdle" value="20"/>
<property name="maxActive" value="200"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="255000"/>
</bean>
<bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 基本属性 url、user、password -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db2"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="20"/>
<property name="minIdle" value="20"/>
<property name="maxActive" value="200"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="255000"/>
</bean>
<!-- <bean id="dataSource3" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:mysql://192.168.1.246:3306/db3</value>
</property>
<property name="user">
<value>ysb</value>
</property>
<property name="password">
<value>ysb</value>
</property>
<property name="initialPoolSize">
<value>20</value>
</property>
<property name="minPoolSize">
<value>20</value>
</property>
<property name="maxPoolSize">
<value>200</value>
</property>
<property name="maxIdleTime">
<value>255000</value>
</property>
</bean> -->
<bean id="dataSource" class="datasource.DynamicDataSource">
<property name="master" ref="master" />
<property name="slaves">
<list>
<ref bean="dataSource2"/>
<!-- <ref bean="dataSource3"/> -->
</list>
</property>
</bean>