当前位置: 首页 > 工具软件 > Uncode-DAL > 使用案例 >

spring+mybatis+uncode-dal实现数据库读写分离

袁致远
2023-12-01
1.准备工作
搭建本地环境:

virtualbox安装两个fedora虚拟机,部署流复制主从postgres数据库在两台机器上 

部署应用,测试应用是否可以访问主库

搭建流复制环境参考http://www.sijitao.net/1764.html

要注意的事项是:
从库不需要initdb
pg_basebackup到从库的目录所属用户应该是postgres:postgres
需要将 wal_keep_segments设为一个比较大的值譬如32,防止在创建从库的过程中有些segment被删除了,导致从库起不起来 

2.代码实现
uncode-dal使用

其原理是根据不同的操作,设置不同的route,从而选择不同的datasource
例如调用其insert方法,先设置route为写,那么只会从主datasource中获得连接
具体代码逻辑是 
a.设置 DBContextHolder的该线程的thread local中值为write
b.调用动态数据源的getConnection的时候判断当前线程的thread local中的值,如果是write,
从主datasource获得connection
如果是read,从多个slaveDataSource中随机的获得一个datasource,并获得其连接

c.如果连续三次获得datasource连接失败(对应应用的三次数据库操作),
如果是读操作,那么将这个失败的从库datasource 从从库list中删除
如果是写操作,那么切换当前datasource为主库,备库中的一个( 原来是主库,如果当前从库可用,切换为从库,对原来是从库也是同样的逻辑),这个就导致数据库切换太慢了,可以根据具体的业务场景做优化

由于使用了threadlocal,所以多个线程同时执行数据库操作,获取datasource的逻辑也不会出错

3.spring+mybatis+uncode dal
spring applicationcontext.xml
1.配置多个数据源,建议使用druiddatasource
<bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"
    ...
</bean>

<bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"
      destroy-method="close">
   ...
</bean>

2.配置uncode动态数据源,指定主库,备库(用于写操作),从库(用于读操作)
<bean id="dynamicDataSource" class="cn.uncode.dal.datasource.DynamicDataSource">
    <property name="slaveDataSources>//设置从库,读操作从这些数据库中读
        <map key-type="java.lang.String">
            <entry key="readDataSourceOne" value-ref="dataSource2"/> (可配置多个)
        </map>
    </property>
    <!-- 主数据库配置 -->
    <property name="masterDataSource" ref="dataSource1" />
   <property name="standbyDataSource" ref=“dataSource2”/ >
</bean>

<bean id="transactionManager" class="cn.uncode.dal.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dynamicDataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
3.指定mybatis mapper配置文件及dao类位置,需指定datasource为上面定义的动态数据源
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dynamicDataSource" />
    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
    <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
</bean>
<bean id="sqlSessionTemplateSimple" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory" />
    <!--更新采用单个模式 -->
    <constructor-arg index="1" value="SIMPLE" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="...dao(包名)" />
    <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplateSimple" />
</bean>
4.那么在使用dao的时候,可以先指定是读操作还是写操作,然后再调用相应的操作
DBContextHolder.swithToRead();//这里可以定义dao的拦截器,指定某一类方法调用时都先执行这个操作
userDao.getNewAccount("1");

如果想使用其提供的baseDal(但是只支持单表操作)
在上面的applicationcontext.xml中再增加spring-jdbc配置(参加uncode-dal wiki)
java代码调用,见其说明

遇到的问题:
1.流复制从数据库不能启动
原因是主库保留的wal log数目太少,等从库配好启动的时候主库已经有些wal log被删除了
导致从库启动的时候从主库获得不了需要的wal log,需要不能启动

2.虚拟机上各种网络的含义,为啥有时候能联网,有时候不能联网(绕过)
怎么设置静态ip地址(通过界面settings,网络解决,后面看一些怎么通过修改配置文件解决)

3.迁移之后插入新的数据会报
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "index_28"
org.postgresql.util.PSQLException: ERROR: function geometry(text) does not exist
查看已经安装的extension,查看pg_extension视图
说明迁移的时候序列,extension有问题,后面看怎么解决,先绕过

4.如何纪录在每个数据库上执行了哪些操作
通过修改postgresql的log配置解决

5.在maven库中找不到uncode-dal的一些包?
解决方法:将uncode-dal的代码下载下来,重新编译生成jar包在本地



 类似资料: