Druid-源码实践实现一个简单的数据源版本V0.1
- 实现获取连接的时候init数据源
- 实现判断池中连接数量小于最小数量循环创建连接
- 实现创建连接的简单查询
WmyDataSource
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName WmyDataSource.java
* @Description 重新写自己的数据源
* @createTime 2021年11月16日 19:35:00
*/
@Slf4j
public class WmyDataSource implements DataSource {
// 定义最大连接数
private volatile int maxConnection = 10;
// 定义最小连接数
private volatile int minConnection = 3;
// 正在使用的连接 线程安全的队列
private ConcurrentLinkedQueue<WmyPooledConnection> runningConnection = new ConcurrentLinkedQueue<>();
// 空闲的连接 线程安全的队列
private ConcurrentLinkedQueue<WmyPooledConnection> freeConnection = new ConcurrentLinkedQueue<>();
protected ReentrantLock lock = new ReentrantLock();
//池中的连接数量
private int poolingCount;
//是否初始化标记
protected volatile boolean inited = false;
private String username;
private String url;
private String password;
public WmyDataSource( String url, String username,String password) {
this.username = username;
this.url = url;
this.password = password;
}
@Override
public Connection getConnection() throws SQLException {
init();
// 空闲队列为空
if(freeConnection.isEmpty()){
// 创建连接
WmyPooledConnection wmyPooledConnection = new WmyPooledConnection(username, url, password, this);
runningConnection.add(wmyPooledConnection);
return wmyPooledConnection.getConnection();
}
//不为空直接取
WmyPooledConnection poll = freeConnection.poll();
runningConnection.add(poll);
return poll.getConnection();
}
private void init() throws SQLException {
if(inited){
return;
}
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
throw new SQLException("interrupt", e);
}
//池中的数量小于最小数量 创建连接
try{
if(poolingCount < minConnection){
// 循环创建连接 poolingCount的数值处理TODO
for(int i=0;i<=minConnection-poolingCount;i++){
WmyPooledConnection wmyPooledConnection = new WmyPooledConnection(username, url, password, this);
freeConnection.add(wmyPooledConnection);
}
}
}catch (SQLException e){
log.error("init datasource error, url: " + this.url, e);
}finally {
inited = true;
lock.unlock();
}
}
......
}
WmyConnectPool
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName WmyConnectPool.java
* @Description 自定义连接池
* @createTime 2021年11月16日 20:01:00
*/
public class WmyPooledConnection implements PooledConnection, Connection {
private String username;
private String url;
private String password;
private Connection connection;
private WmyDataSource dataSource;
// 初始化
public WmyPooledConnection(String username, String url, String password, WmyDataSource dataSource) throws SQLException {
this.username = username;
this.url = url;
this.password = password;
this.dataSource = dataSource;
this.getConnection();
}
......
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}
......
}
Test
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName TestDataSource.java
* @Description 测试数据源
* @createTime 2021年11月16日 19:10:00
*/
public class TestDataSource {
private static String url = "jdbc:mysql://localhost:3306/jk_test?characterEncoding=utf-8";
private static String user = "root";
private static String password = "12345678";
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
for(int i=0;i<10;i++){
//原始jdbc
execuByJDBC();
}
System.out.println("select by jdbc ===={}"+(System.currentTimeMillis()-startTime));
startTime = System.currentTimeMillis();
for(int i=0;i<10;i++){
//自己封装的数据源
execuByWmyDatasource();
}
System.out.println("select by wmyDataSource ===={}"+(System.currentTimeMillis()-startTime));
}
private static void execuByWmyDatasource() {
WmyDataSource dataSource = new WmyDataSource(url, user, password);
Connection connection = null;
String sql = "select * from jk_goods";
PreparedStatement ps = null;
ResultSet rs = null;
try {
connection = dataSource.getConnection();
ps = connection.prepareStatement(sql);
rs = ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
ps.close();
rs.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void execuByJDBC() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.加载驱动程序
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得数据库链接
conn = DriverManager.getConnection(url, user, password);
String sql = "select * from jk_goods";
//3.通过数据库的连接操作数据库,实现增删改查
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
ps.close();
rs.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
结果
select by jdbc ===={}1683
select by wmyDataSource ===={}1487
总结
今天通过对之前源码的解读进行了自定义数据源的尝试,实现自定义数据源连接和执行sql的操作,这次实现的是0.1版本,后续针对自己对holder的理解,增加holder层的处理。在实际编写自定义数据源的实践过程中,才发现之前自己看的有点太粗了,很多细节没有注意到,正好在完善自定义数据源的过程中再复习巩固一次。