概述
写一个JDBC驱动
一. 前言
在前上一章教程中,介绍了用SQL查询远程文件。
本章将在上一章的基础上,进一步扩展程序。
注:
1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题。
2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓。
学习本章需要准备的知识:
1.读完本系列教程的前面章节。
2.理解JDBC。
二. 步入正题
话不多说,大家自己理解,下面步入正题:
既然使用SQL查询文件,那么我们可以为这个程序写一个JDBC驱动,这样就能象访问数据库一样访问文件了。
下面我带大家一步一步实现JDBC的驱动程序。
JDBC(Java Database Connectivity)是Java提供的一套与数据库交互的规范,该规范用接口形式来描述,
即如果你的产品要允许Java程序员通过JDBC规范(接口)来进行访问,那么你必须提供一套符合该规范(接口)的驱动程序。
JDBC规范的相关接口都在java.sql包中定义。
最常见接口有:
java.sql.Driver:驱动程序规范
java.sql.Connection:与数据库连接的相关操作
java.sql.Statement:与数据库进行SQL交互的相关操作
java.sql.ResultSet:对查询结果的相关操作
常见的操作如下:
1 //加载驱动程序 2 Class.forName("com.mysql.jdbc.Driver"); 3 //连接数据库 4 Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/DB", "testuser", "testpass"); 5 //创建执行SQL的类 6 Statement st = conn.createStatement(); 7 //执行SQL,查询结果 8 ResultSet rs = st.executeQuery("select * from xxx"); 9 10 //遍历查询结果 11 while(rs.next()) { 12 System.out.print(rs.getString(1)); 13 } 14 15 //关闭资源 16 rs.close(); 17 st.close(); 18 conn.close();
下面依次介绍程序写法:
1.加载驱动程序
用Class.forName方式加载,即执行目标类的静态块,把驱动程序放在静态块中,保证了该驱动只被加载一次的特性。
另外一个好处是驱动类的名字是用字符串传入的,在工程编译阶段不依赖具体的驱动程序。
获得数据库连接是一切操作开始的根源,在JDBC规范中,用如下方式来获取数据库的连接:
DriverManager.getConnection(...)
我们可以通过源代码看一下DriverManager.getConnection的大致流程:
源代码如下:
1 private static Connection getConnection( 2 String url, java.util.Properties info, Class<?> caller) throws SQLException { 3 /* 4 * When callerCl is null, we should check the application's 5 * (which is invoking this class indirectly) 6 * classloader, so that the JDBC driver class outside rt.jar 7 * can be loaded from here. 8 */ 9 ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; 10 synchronized(DriverManager.class) { 11 // synchronize loading of the correct classloader. 12 if (callerCL == null) { 13 callerCL = Thread.currentThread().getContextClassLoader(); 14 } 15 } 16 17 if(url == null) { 18 throw new SQLException("The url cannot be null", "08001"); 19 } 20 21 println("DriverManager.getConnection("" + url + "")"); 22 23 // Walk through the loaded registeredDrivers attempting to make a connection. 24 // Remember the first exception that gets raised so we can reraise it. 25 SQLException reason = null; 26 27 for(DriverInfo aDriver : registeredDrivers) { 28 // If the caller does not have permission to load the driver then 29 // skip it. 30 if(isDriverAllowed(aDriver.driver, callerCL)) { 31 try { 32 println(" trying " + aDriver.driver.getClass().getName()); 33 Connection con = aDriver.driver.connect(url, info); 34 if (con != null) { 35 // Success! 36 println("getConnection returning " + aDriver.driver.getClass().getName()); 37 return (con); 38 } 39 } catch (SQLException ex) { 40 if (reason == null) { 41 reason = ex; 42 } 43 } 44 45 } else { 46 println(" skipping: " + aDriver.getClass().getName()); 47 } 48 49 } 50 51 // if we got here nobody could connect. 52 if (reason != null) { 53 println("getConnection failed: " + reason); 54 throw reason; 55 } 56 57 println("getConnection: no suitable driver found for "+ url); 58 throw new SQLException("No suitable driver found for "+ url, "08001"); 59 }
首先遍历已经注册的驱动程序,
用连接字符串,用户名,密码作为参数来调用每个驱动程序的connect方法,
如果该驱动程序返回结果不是null,则认为找到该驱动程序,并且返回使用该驱动程序生成的与数据库的连接。
所以,我们必须首先在DriverManager中注册我们的驱动程序。
我们写一个符合java.sql.Driver的类,如下:
1 public class MyDriver implements Driver{ 2 3 static { 4 try { 5 // 注册驱动程序 6 DriverManager.registerDriver(new MyDriver()); 7 } catch (SQLException e) { 8 e.printStackTrace(); 9 } 10 } 11 ......
2.连接数据库
接下来,要通过传入的连接字符串和用户名密码信息来连接数据库。
在connect()方法判断是否是合法的连接字符串,如果是则连接数据库并返回自定义的MyConnection。
1 /** 2 * @author http://www.java123.vip 3 * 4 * @param url 5 * @param info 6 */ 7 public Connection connect(String url, Properties info) throws SQLException { 8 9 String protocal = url.split(":")[0]; 10 String productor = url.split(":")[1]; 11 12 // 只处理连接字符串包括jdbc和my的请求 13 if("jdbc".equals(protocal) && "my".equals(productor)) { 14 String ip = url.split(":")[2]; 15 int port = Integer.valueOf(url.split(":")[3]).intValue(); 16 String username = info.getProperty("user"); 17 String password = info.getProperty("password"); 18 19 MyConnection myConnection = new MyConnection(ip,port,username,password); 20 21 return myConnection; 22 } else { 23 return null; 24 } 25 26 27 } 28 29 ......其他接口略
3.创建执行SQL的类
MyConnection的构造方法中,初始化输入输出流,用来与远程数据库进行通讯。
在createStatement()方法中,用输入输出流作为参数初始化并返回自定义的MyStatement。
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class MyConnection implements Connection{ 7 8 private Socket socket; 9 private BufferedReader br; 10 private PrintWriter pw; 11 12 public MyConnection(String ip, int port, String username, String password) { 13 14 try { 15 16 socket = new Socket(ip, port); 17 InputStream is = socket.getInputStream(); 18 InputStreamReader isr = new InputStreamReader(is); 19 br = new BufferedReader(isr); 20 21 OutputStream os = socket.getOutputStream(); 22 OutputStreamWriter osw = new OutputStreamWriter(os); 23 pw = new PrintWriter(osw,true); 24 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 29 } 30 31 public Statement createStatement() throws SQLException { 32 MyStatement st = new MyStatement(br,pw); 33 return st; 34 } 35 36 public void close() throws SQLException { 37 38 try { 39 pw.println("bye:bye"); 40 socket.close(); 41 } catch (IOException e) { 42 e.printStackTrace(); 43 } 44 45 } 46 ......其他接口略
4.执行SQL,查询结果
在MyStatement的作一个executeQuery()方法,将传入的sql发送给远程数据库,并且将返回的结果封装成自定义的结果及MyResultSet,
我们延用上一章的方法,向服务器发送查询请求,并且将结果保存在MyResultSet中:
代码如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class MyStatement implements Statement{ 7 8 private BufferedReader br; 9 private PrintWriter pw; 10 11 public MyStatement(BufferedReader br,PrintWriter pw) { 12 this.br = br; 13 this.pw = pw; 14 } 15 16 public ResultSet executeQuery(String sql) throws SQLException { 17 18 MyResultSet mrs = new MyResultSet(); 19 20 try { 21 pw.println("query:"+sql); 22 23 while(true) { 24 String queryResultLine = br.readLine(); 25 26 if("".equals(queryResultLine)) { 27 break; 28 }else { 29 mrs.addData(queryResultLine.split(",")); 30 } 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 36 return mrs; 37 } 38 ......其他接口略
5.遍历查询结果
我们做一个MyResultSet来实现对查询结果的存取操作,代码如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class MyResultSet implements ResultSet{ 7 8 private List<String[]> dataList = new ArrayList<String[]>(); 9 private int cursor = -1; 10 11 public MyResultSet() { 12 13 } 14 15 public void addData(String[] data) { 16 dataList.add(data); 17 } 18 19 public boolean next() throws SQLException { 20 if(cursor + 1 >= dataList.size()) { 21 return false; 22 }else { 23 cursor ++ ; 24 return true; 25 } 26 } 27 28 public void close() throws SQLException { 29 30 } 31 32 public String getString(int columnIndex) throws SQLException { 33 String[] rowData = dataList.get(cursor); 34 return rowData[columnIndex-1]; 35 } 36 ......其他接口略
三. 测试
测试程序如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class FileViewClientJDBC { 7 8 public static void main(String[] args) { 9 10 try { 11 Class.forName("vip.java123.fileview.client.jdbc.dirver.MyDriver"); 12 Connection conn = DriverManager.getConnection("jdbc:my:127.0.0.1:8000", "testuser", "testpass"); 13 Statement st = conn.createStatement(); 14 ResultSet rs = st.executeQuery("select * from abc.csv"); 15 16 while(rs.next()) { 17 System.out.print(rs.getString(1) + ","); 18 System.out.print(rs.getString(2) + ","); 19 System.out.println(rs.getString(3)); 20 } 21 22 rs.close(); 23 st.close(); 24 conn.close(); 25 26 } catch (ClassNotFoundException e) { 27 e.printStackTrace(); 28 } catch (SQLException e) { 29 e.printStackTrace(); 30 } 31 } 32 }
启动服务器,输出如下:
listening at port:8000
启动测试程序,输出如下:
1,abc,aaa
2,def,bbb
3,xyz,ccc
服务器输出
listening at port:8000
get connection:/127.0.0.1
get message:query:select * from abc.csv
get message:bye:bye
完整程序请大家从[这里]下载
如有问题,大家来我的网站进行提问。
https://www.java123.vip/qa
版权声明:本教程版权归java123.vip所有,禁止任何形式的转载与引用。
转载于:https://www.cnblogs.com/java123-vip/p/9744782.html
最后
以上就是犹豫蚂蚁为你收集整理的Java学习不走弯路教程(5.写一个JDBC驱动)的全部内容,希望文章能够帮你解决Java学习不走弯路教程(5.写一个JDBC驱动)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复