Spring-Boot快速集成Sqlite数据库(动态创建,动态切换)
首先分析集成sqlite,然后需要完成的需求
- 动态创建sqlite数据
- 动态连接sqlite数据库
- 操作sqlite数据库
相比较传统的数据,使用mybaits集成,需要变更是数据库驱动driver,这个需要引入sqlite的依赖
<dependencies>
<!--mybaits-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- sqlite3驱动包 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.27.2.1</version>
</dependency>
</dependencies>
配置初始sqlite数据库
# database configuration
blog.sqlite.url: jdbc:sqlite:E:/git_space/BlogSqlite/sqlite/pro.db
这里配置的是初始的数据库,文件不用创建,项目启动时会自动创建并初始化数据的表
@MapperScan(basePackages = {"club.dlblog.sqlite.mapper"},
sqlSessionFactoryRef = "sqlSessionFactory")
@Configuration
public class SqliteConfig {
//数据源url
@Value("${blog.sqlite.url}")
private String dataSourceUrl;
/**
* 配置sqlite数据源
* @return
*/
@Bean(name = "sqliteDataSource")
public DataSource sqliteDataSource(){
//尝试创建sqlite文件-不存在时创建
SqliteUtils.initSqliteFile(SqliteUtils.getFilePath(dataSourceUrl));
//创建数据源
DataSource dataSource = SqliteBuilder.create().url(dataSourceUrl).build();
try {
//尝试初始化数据库-表不存在时创建
SqliteUtils.initProDb(dataSource.getConnection());
} catch (SQLException e) {
e.printStackTrace();
}
return dataSource;
}
/**
* session工厂
*/
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(
@Qualifier("dynamicDataSource") DynamicDataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().
getResources("classpath:mapper/**/*.xml"));
return sessionFactoryBean.getObject();
}
/**
* session模板
* @param sqlSessionFactory
* @return
*/
@Bean(name = "sqlSessionTemplate")
public SqlSessionTemplate ComSqlSessionTemplate(
@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
/**
* 动态数据源
* @param dataSource
* @return
*/
@Bean(name = "dynamicDataSource")
public DynamicDataSource dynamicDataSource(@Qualifier("sqliteDataSource") DataSource dataSource){
return new DynamicDataSource(dataSource);
}
}
在这里需要做两步操作,尝试创建文件,文件不存在时,则去创建文件
//创建sqlite文件
public static void initSqliteFile(String filePath){
File file = new File(filePath);
File dir = file.getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
尝试初始化数据库,当表不存在时初始化数据
/**
* 初始化项目db
* @param connection
*/
public static void initProDb(Connection connection){
//判断数据表是否存在
boolean hasPro = false;
try {
hasPro = true;
//测试数据表是否存在
connection.prepareStatement("select * from pro").execute();
}catch (SQLException e){
//不存在
logger.debug("table pro is not exist");
hasPro = false;
}
//不存在时创建db
if(!hasPro) {
logger.debug(">>>start init pro db");
File file = null;
try {
//读取初始化数据sql
file = ResourceUtils.getFile("classpath:sql/init.sql");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//获取sql
String sql = "";
FileInputStream fis = null;
InputStreamReader isr = null;
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis, "UTF-8");
BufferedReader bf = new BufferedReader(isr);
String content = "";
StringBuilder sb = new StringBuilder();
while (content != null) {
content = bf.readLine();
if (content == null) {
break;
}
sb.append(content.trim());
}
sql = sb.toString();
} catch (FileNotFoundException | UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
isr.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//分割sql
String[] sqls = sql.split(";");
try {
for (String str : sqls) {
//开始初始化数据库
connection.setAutoCommit(false);
connection.prepareStatement(str).execute();
}
//提交sql
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
logger.debug("finish init pro db>>>");
}else {
logger.debug("pro db is exist");
}
}
构建sqlite数据源其实只需要url和驱动类
下面时创建sqlite数据源的方式
public DataSource build(){
//url不为空
if (url!=null&&url!=""){
return DataSourceBuilder.create().
url(url).driverClassName(JDBC.class.getName()).build();
}
//文件路径不为空
if(filePath!=null&&filePath!=""){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("jdbc:sqlite:").append(filePath);
return DataSourceBuilder.create().
url(stringBuilder.toString()).driverClassName(JDBC.class.getName()).build();
}
return DataSourceBuilder.create().build();
}
创建动态sqlite数据源
参照我的上一篇的动态数据源的集成方式
动态数据源创建方式
/**
* 动态数据源配置
* @author machenike
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private volatile static DynamicDataSource dynamicDataSource;
/**
* 数据源存储用map
*/
private final Map<Object,Object> dataSourceMap = new ConcurrentHashMap<>();
/**
* 当前线程数据源key
*/
private final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
@Override
protected Object determineCurrentLookupKey() {
//弹出当前数据源key
return contextHolder.get();
}
/**
* 动态数据源构造方法
* @param defaultDataSource
*/
public DynamicDataSource(DataSource defaultDataSource) {
//存入主数据源
dataSourceMap.put("master",defaultDataSource);
//设定目标数据源map
setTargetDataSources(dataSourceMap);
//设定默认数据源
setDefaultTargetDataSource(defaultDataSource);
dynamicDataSource = this;
}
/**
* 判断当前数据源是否存在
*
* @param dataBaseKey
* @return
*/
public static boolean isExistDataSource(String dataBaseKey) {
if (dynamicDataSource != null) {
return dynamicDataSource.getDataSourceMap().containsKey(dataBaseKey);
} else {
return false;
}
}
/**
* 切换数据源
*
* @param key
*/
public static void setDataSourceKey(String key) {
if (dynamicDataSource != null) {
dynamicDataSource.getContextHolder().set(key);
dynamicDataSource.afterPropertiesSet();
}
}
/**
* 获取当前数据源
*
* @return
*/
public static String getDataSourceKey() {
if (dynamicDataSource != null) {
return dynamicDataSource.getContextHolder().get();
} else {
return null;
}
}
/**
* 切换到默认数据源
*/
public static void clearDataSourceKey() {
if (dynamicDataSource != null) {
dynamicDataSource.getContextHolder().remove();
}
}
/**
* 根据数据源key设置数据源
*
* @param datatBase
* @return
*/
public static void addDataSource(String datatBase, DataSource dataSource) {
if (dynamicDataSource == null) {
return;
}
// 没有数据源时添加数据源,有数据源直接使用
if (!isExistDataSource(datatBase)) {
// 新增数据源
dynamicDataSource.getDataSourceMap().put(datatBase, dataSource);
}
// 切换数据源
checkoutDataSource(datatBase);
}
/**
* 切换数据源
*
* @param databaseKey
*/
public static void checkoutDataSource(String databaseKey) {
if (dynamicDataSource != null) {
// 切换数据源
setDataSourceKey(databaseKey);
dynamicDataSource.afterPropertiesSet();
}
}
}
整个流程
- 项目启动时尝试去链接本地的sqlite数据库
- 当文件不存在创建文件
- 当数据表不存在创建表
- 同时将主数据源放入动态数据源中
- 启动完主数据库完成链接绑定mapper
后续创建数据源的步骤
- 创建sqlite文件
- 初始化数据库
- 创建新的数据源放入动态数据
- 通过动态数据源来切换数据库