配置动态数据源
jdbc是直接获取数据库连接,然后操作数据库的过程。
数据源是借鉴了”池“的思想,从数据库连接池里获取数据库连接。
jdbc使用流程,如下
//网上jdbc使用模板比较多,比如 https://blog.csdn.net/Yuz_99/article/details/89763803
//加载数据库驱动程序(对应的Driver 实现类中有注册驱动的静态代码块)
Class.forName(driver);
//通过DriverManager 的getConnection() 方法获取数据库连接.
Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
...close();
rs.close();
statement.
...
//关闭数据库连接
close(); conn.
而datasource,从下面可以看到,连接池也有getConnection方法。
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package javax.sql;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Wrapper;
/**
* <p>A factory for connections to the physical data source that this
* {@code DataSource} object represents. An alternative to the
* {@code DriverManager} facility, a {@code DataSource} object
* is the preferred means of getting a connection. An object that implements
* the {@code DataSource} interface will typically be
* registered with a naming service based on the
* Java™ Naming and Directory (JNDI) API.
* <P>
* The {@code DataSource} interface is implemented by a driver vendor.
* There are three types of implementations:
* <OL>
* <LI>Basic implementation -- produces a standard {@code Connection}
* object
* <LI>Connection pooling implementation -- produces a {@code Connection}
* object that will automatically participate in connection pooling. This
* implementation works with a middle-tier connection pooling manager.
* <LI>Distributed transaction implementation -- produces a
* {@code Connection} object that may be used for distributed
* transactions and almost always participates in connection pooling.
* This implementation works with a middle-tier
* transaction manager and almost always with a connection
* pooling manager.
* </OL>
* <P>
* A {@code DataSource} object has properties that can be modified
* when necessary. For example, if the data source is moved to a different
* server, the property for the server can be changed. The benefit is that
* because the data source's properties can be changed, any code accessing
* that data source does not need to be changed.
* <P>
* A driver that is accessed via a {@code DataSource} object does not
* register itself with the {@code DriverManager}. Rather, a
* {@code DataSource} object is retrieved though a lookup operation
* and then used to create a {@code Connection} object. With a basic
* implementation, the connection obtained through a {@code DataSource}
* object is identical to a connection obtained through the
* {@code DriverManager} facility.
* <p>
* An implementation of {@code DataSource} must include a public no-arg
* constructor.
*
* @since 1.4
*/
public interface DataSource extends CommonDataSource, Wrapper {
/**
* <p>Attempts to establish a connection with the data source that
* this {@code DataSource} object represents.
*
* @return a connection to the data source
* @exception SQLException if a database access error occurs
* @throws java.sql.SQLTimeoutException when the driver has determined that the
* timeout value specified by the {@code setLoginTimeout} method
* has been exceeded and has at least tried to cancel the
* current database connection attempt
*/
Connection getConnection() throws SQLException;
/**
* <p>Attempts to establish a connection with the data source that
* this {@code DataSource} object represents.
*
* @param username the database user on whose behalf the connection is
* being made
* @param password the user's password
* @return a connection to the data source
* @exception SQLException if a database access error occurs
* @throws java.sql.SQLTimeoutException when the driver has determined that the
* timeout value specified by the {@code setLoginTimeout} method
* has been exceeded and has at least tried to cancel the
* current database connection attempt
* @since 1.4
*/
Connection getConnection(String username, String password)
throws SQLException;
}
现在生产环境一般都会引入数据源。一来解耦,二来,很多中间件都是和datasource交互的,不直接通过jdbc获取连接。
场景
参考:Spring项目中使用两种方法动态切换数据源,多数据源切换_u013034378的博客-CSDN博客_动态数据源
一般有两种动态切换数据库的场景。 场景一:数据源信息配置在xml中,适用于一般数据库切换。执行完某操作,切换数据库,执行另一个操作。 场景二:数据源信息配置在默认数据源中,适用于切换数据库操作同一方法,相当于批量执行方法。
场景二的实现
我遇到的情况是,模拟客户端,每个客户端都有一个sqlite库,需要对每个库作相同的操作。
恰好就是场景二,切换数据库操作同一方法。
package com.ycb.dao.datasource;
import org.springframework.jdbc.datasource.AbstractDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 动态数据源(一次性,用完即丢,没注册bean)
*/
public class DynamicDataSource extends AbstractDataSource {
public DynamicDataSource() {
}
protected DataSource determineTargetDataSource() {
return DataSourceHolder.getDataSource();
}
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return (T) this;
}return determineTargetDataSource().unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
}
}
//public class DynamicDataSourceV1 extends AbstractRoutingDataSource {
// public DynamicDataSource() {}
//
// @Override
// protected DataSource determineTargetDataSource() {
// return DataSourceHolder.getDataSource();
// }
//
// @Deprecated
// @Override
// protected Object determineCurrentLookupKey() {
// return null;
// }
//
// @Deprecated
// @Override
// public void afterPropertiesSet() {
// }
//}
这是每次切换数据源,都是新生成一个数据源,没有缓存下来。如果考虑数据源复用,可以用map缓存下来。
package com.ycb.dao.datasource;
import com.ycb.dao.db.SqliteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.sqlite.JDBC;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
/**
* 封装的对数据源进行操作的类:
*/
public class DataSourceHolder {
private static Logger logger = LoggerFactory.getLogger(DataSourceHolder.class);
//线程 本地环境
private static final ThreadLocal<DataSource> dataSources = new InheritableThreadLocal<>();
//设置数据源
public static void setDataSource(String jdbcUrl) {
DataSource dataSource = SqliteUtil.createDateSource(jdbcUrl);
set(dataSource);
dataSources.
}
//设置数据源
public static void setDataSource(DataSource datasource) {
set(datasource);
dataSources.
}
//获取数据源
public static DataSource getDataSource() {
return dataSources.get();
}
//清除数据源
public static void clearDataSource() {
remove();
dataSources.
} }
使用
setDataSource(jdbcUrl);
DataSourceHolder.//...
//...
clearDataSource(); DataSourceHolder.
参考:Spring Boot + Mybatis 实现动态数据源 – 朝雨忆轻尘 – 博客园 (cnblogs.com)
发表回复