在此一写多读模式下解决了sqlite SQLITE_LOCKED问题,此模式已在生产环境中测试通过,性能比单连接至少要高出几十倍,极端接口能高出几百倍
项目地址:https://github.com/ayzhouwen/zwSqliteTest
实现原理精要
1.sqlite 本身是不支持多连接并发写入的,所以必须是单连接写入,所以可以用单写+多读可以来提高程序整体性能
2.文中说的一写多读是指的同一个数据库下一个连接写,多个连接读,并不是多个库的读写分离
3.具体配置跟mysql等其他数据库的读写分离配置差不多,
这里只贴出最核心的配置,具体的参考项目代码
package com.zw.sqliteTest.config.db;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteOpenMode;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* sqlite 一写多读,性能起飞
*/
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.driver-class-name}")
private String driverName;
@Value("${spring.datasource.url}")
private String url;
/**
* 业务主数据库
* @return DataSource
*/
@Bean("masterDataSource")
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName(driverName);
hikariConfig.setJdbcUrl(url);
hikariConfig.setMaximumPoolSize(1);
hikariConfig.setConnectionTestQuery("SELECT 1");
//在数据源设置打开模式属性值然后在传递给jdbc
SQLiteConfig config= new SQLiteConfig();
config.setOpenMode(SQLiteOpenMode.OPEN_URI);
config.setOpenMode(SQLiteOpenMode.FULLMUTEX);
config.setBusyTimeout(10000);
hikariConfig.setPoolName("springHikariCP");
hikariConfig.addDataSourceProperty(SQLiteConfig.Pragma.OPEN_MODE.pragmaName, config.getOpenModeFlags());
hikariConfig.addDataSourceProperty(SQLiteConfig.Pragma.JOURNAL_MODE.pragmaName, SQLiteConfig.JournalMode.WAL );
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
return dataSource;
}
/**
* 从数据库
* @return DataSource
*/
@Bean("slaveDataSource")
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName(driverName);
hikariConfig.setJdbcUrl(url);
Integer busThreadNum=Runtime.getRuntime().availableProcessors();
hikariConfig.setMaximumPoolSize(2*busThreadNum);
hikariConfig.setConnectionTestQuery("SELECT 1");
//在数据源设置打开模式属性值然后在传递给jdbc
SQLiteConfig config= new SQLiteConfig();
config.setOpenMode(SQLiteOpenMode.OPEN_URI);
config.setOpenMode(SQLiteOpenMode.READWRITE);
config.setOpenMode(SQLiteOpenMode.NOMUTEX);
config.setBusyTimeout(10000);
hikariConfig.setPoolName("springHikariCP");
hikariConfig.addDataSourceProperty(SQLiteConfig.Pragma.OPEN_MODE.pragmaName, config.getOpenModeFlags());
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
return dataSource;
}
/**
* 数据源路由
* @param masterDataSource 主数据库
* @param slaveDataSource 从数据库
* @return DataSource
*/
@Bean
public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.WORKDB_MASTER, masterDataSource);
targetDataSources.put(DBTypeEnum.WORKDB_SLAVE, slaveDataSource);
MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();
myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);
myRoutingDataSource.setTargetDataSources(targetDataSources);
return myRoutingDataSource;
}
}