为“自研”的KV数据库编写JDBC驱动

一觉醒来,受到梦的启发,自研了一套K/V数据库系统,因为"客户"一直催促我提供数据库的JDBC驱动,无奈之下,只好花费一个上午的时间为用户编写一个。

我们知道,JDBC只定义一系列的接口, 具体的实现需要由不同厂商提供的,我们首先需要实现java.sql.Driver这个接口:

package org.littlestar.propsjdbc;
//import ...
public class Driver implements java.sql.Driver {
	// 当class loader加载本类时,向DriverManager注册该驱动
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException e) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    
	@Override
	public Connection connect(String url, Properties info) throws SQLException {
		return new ConnectionImpl(url);
	}

	@Override
	public boolean acceptsURL(String url) throws SQLException {
		if (url == null) {
			throw new SQLException("url is null.");
		}
		// 接受'jdbc:props:'类型的URL
		return url.trim().startsWith("jdbc:props:");
	}
	// ... 其它接口实现省略
}

DriverManager是通过JDK内置的SPI(Service Provider Interface)机制来发现我编写的’org.littlestar.propsjdbc.Driver’实现。所以我们需要在META-INF/services/目录里创建一个以服务接口命名的文件, 文件名为"java.sql.Driver"的文件, 该文件内容为接口实现类: ‘org.littlestar.propsjdbc.Driver’。当DriverManager在调ensureDriversInitialized()方法的时候,ServiceLoader会查找类路径下的META-INF/services/java.sql.Driver文件,并加载其定义的接口实现类。

private static void ensureDriversInitialized() {
	//...
	ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
	Iterator<Driver> driversIterator = loadedDrivers.iterator();
    /* Load these drivers, so that they can be instantiated...*/
	try {
		while (driversIterator.hasNext()) {
			driversIterator.next();
		}
	} catch (Throwable t) {
		// Do nothing
    }
    //...
}

接下来还要分别实现java.sql.Connection,java.sql.Statement和java.sql.ResultSet接口:

package org.littlestar.propsjdbc;
// import ...;
public class ConnectionImpl implements java.sql.Connection {
	String dbPath = System.getProperty("user.dir");
	public ConnectionImpl(String url) {
		if (url != null) {
			dbPath = url.trim().replaceFirst("jdbc:props:", "").trim();
		}
	}

	@Override
	public Statement createStatement() throws SQLException {
		return new StatementImpl(dbPath);
	}
	// ... 其它接口实现省略
}

编写java.sql.Statement接口的实现:

package org.littlestar.propsjdbc;
// import ...;
public class StatementImpl implements java.sql.Statement {
	String dbPath = "";
	public StatementImpl(String path) {
		dbPath = path;
	}
	
	@Override
	public ResultSet executeQuery(String sql) throws SQLException {
		String pattern = "(?i)SELECT.*?FROM";
		String fileName = sql.replaceFirst(pattern, "").trim();
		Properties props = new Properties();
		String file = dbPath + File.separator + fileName;
		try (BufferedReader reader = Files.newBufferedReader(Paths.get(file), StandardCharsets.UTF_8)) {
			props.load(reader);
		} catch (IOException e) {
			throw new SQLException(e);
		}
		return new ResultSetImpl(props);
	}
	// ... 其它接口实现省略
}

编写java.sql.ResultSet实现:

package org.littlestar.propsjdbc;
//import ...
public class ResultSetImpl implements java.sql.ResultSet {
	final Properties props;
	Iterator<Entry<Object, Object>> iterator;
	Entry<Object, Object> row;
	public ResultSetImpl(Properties props) {
		this.props = props;
		iterator = props.entrySet().iterator();
	}
	
	@Override
	public boolean next() throws SQLException {
		boolean next = iterator.hasNext();
		if (next) {
			row = iterator.next();
		}
		return next;
	}

	@Override
	public String getString(int columnIndex) throws SQLException {
		if (row == null) {
			return null;
		}
		if (columnIndex == 1) {
			return row.getKey().toString();
		} else if (columnIndex == 2) {
			return row.getValue().toString();
		} else {
			return null;
		}
	}
	// ... 其它接口实现省略
}	

至此,jdbc驱动已经开发完毕,我们打包交给客户测试。Eclipse选择我们的项目,右键菜单选择"Export…“。在弹出的向导菜单中选择"JAR file”,然后点击下一步按钮。
在这里插入图片描述
点击结束按钮既可生成驱动的jar文件。交给用户测试。

测试如下。。。。先通过数据库管理工具"explorer.exe",创建一个"数据库":“D:\testcase\nbdb”,然后通过数据库开发工具“notepad.exe”创建一个表’table1’,内容如下:

名称=牛B数据库系统®
版本=高级企业版本(v24.4)
售价=60000000马内
供应商=白日梦股份有限公司

点击"保存"提交。接下来通过jdbc进行数据库访问:

public class Test {
	public static void main(String[] args) throws SQLException {
		String url = "jdbc:props:D:\\testcase\\nbdb";
		try (Connection connection = DriverManager.getConnection(url);
				Statement stmt = connection.createStatement();
				ResultSet rs = stmt.executeQuery("select * from table1")) {
			// System.out.println(connection.getClass().getCanonicalName());
			// System.out.println(stmt.getClass().getCanonicalName());
			// System.out.println(rs.getClass().getCanonicalName());
			while (rs.next()) {
				String key = rs.getString(1);
				String value = rs.getString(2);
				System.out.println(key + ": " + value);
			}
		}
	}
}
// 程序执行结果如下:
售价: 60000000马内
名称:B数据库系统®
版本: 高级企业版本(v24.4)
供应商: 白日梦股份有限公司

经过"客户"专家组评审,这套数据库系统测试符合预期,达到了业界领先水平,喜提6000w马内,实现人生财富自由。爽文至此结束。各位看官学废了吗?

最后附上完整代码(如果文件审核能过。。。),https://download.youkuaiyun.com/download/Li_Xiang_996/89071254

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值