代码的二次重构(开篇:JDBC连接数据库)
Java中使用JDBC连接数据库时,若是使用初级的代码,代码复用率非常低,连接过程简单来说分为以下几个步骤:
加载驱动包
准备好URL链接获取数据库连接(driver和url根据不同的数据库的不同而不同)
准备sql语句,对数据库进行增删改查四个基础操作,获取数据并处理
关闭与数据库的连接
(与此同时整个过程还要注意进行异常处理)
以上详细步骤可参考博客:http://www.cnblogs.com/erbing/p/5805727.html
加载JDBC驱动程序 → 建立数据库连接Connection → 创建执行SQL的语句Statement → 处理执行结果ResultSet → 释放资源
那么针对以上步骤,在大型项目开发中是无法采纳的,原因有:(1)代码的重用程度低,这种编码方式将造成大量的代码冗余,增加程序员负担(2)整个过程采用硬编码,当需要修改系统配置如:更换数据库时,需要重新编码及发布等等;那么为了避免这些缺点,让我们在开发的过程中将主要的精力都放在针对处理SQL语句及其关键参数上,我们需要对以上代码进行二次重构,做出我们自己的接口;
简单分析,使用JDBC的目的是为了在java代码中使用sql语句对数据库进行增删改查(也就是:查询及修改两个操作,我们将增删改三个操作都视为修改操作),那么我们在开发的过程中,若是只要使用查询和修改的两个接口对数据库进行操作,将大大减轻我们的工作量,我们将这两个接口分别命名为:findBySQL和exeuteUpdate,详细实现代码请见下:
1 package com.neu.dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.ResultSetMetaData; 7 import java.sql.SQLException; 8 import java.util.ArrayList; 9 import java.util.HashMap; 10 import java.util.List; 11 12 import com.neu.util.DBManager; 13 14 public class BaseDao { 15 private Connection conn; 16 private PreparedStatement stmt; 17 private ResultSet rst; 18 19 public int exeuteUpdate(String sql,Object...args){ 20 //Object...args是java中的可变长参数列表的语法,可以按照规则向其传输sql语句需要的所有参数 21 int count=0; 22 try { 23 conn=DBManager.getConnection(); 24 stmt=conn.prepareStatement(sql); 25 if(args!=null){ 26 for(int i=0;i<args.length;i++){ 27 stmt.setObject(i+1, args[i]); 28 } 29 } 30 count=stmt.executeUpdate(); 31 } catch (SQLException e) { 32 throw new RuntimeException("执行sql语句有误",e); 33 }finally{ 34 DBManager.close(conn, stmt, rst); 35 } 36 return count; 37 } 38 39 //不需要提供列名,只需要sql语句和参数即可 40 public List<HashMap<String, String>> findBySQL(String sql, 41 Object...params){ 42 // <>表示 泛型 43 // 保存所有行中的数据 44 List<HashMap<String, String>> list= 45 new ArrayList<HashMap<String,String>>(); 46 // 保存每一行中的每一列数据 47 HashMap<String, String> item=null; 48 try { 49 conn=DBManager.getConnection(); 50 stmt=conn.prepareStatement(sql); 51 if(params!=null){ 52 for(int i=0;i<params.length;i++){ 53 stmt.setObject(i+1, params[i]); 54 } 55 } 56 rst=stmt.executeQuery(); 57 //可以获取查询的列数目 58 ResultSetMetaData meta=rst.getMetaData(); 59 int count=meta.getColumnCount(); 60 String[] colNames=new String[count]; 61 for(int i=0;i<count;i++){ 62 colNames[i]=meta.getColumnName(i+1); 63 } 64 //System.out.println(Arrays.toString(colNames)); 65 while(rst.next()){ 66 item=new HashMap<String, String>(); 67 for(int i=0;i<count;i++){ 68 String value=rst.getString(colNames[i]); 69 item.put(colNames[i].toLowerCase(), value); 70 } 71 list.add(item); 72 } 73 } catch (SQLException e) { 74 throw new RuntimeException("执行查询异常", e); 75 } finally{ 76 DBManager.close(conn, stmt, rst); 77 } 78 return list; 79 } 80 }
1 package com.neu.util; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 9 public class DBManager { 10 private static final String driver; 11 private static final String url; 12 private static final String user; 13 private static final String pwd; 14 /* 15 * 静态块,自在类加载的时候执行一次 16 */ 17 static{ 18 driver=ReadProperties.getInstance() 19 .getProperty("driver"); 20 url=ReadProperties.getInstance() 21 .getProperty("url"); 22 user=ReadProperties.getInstance() 23 .getProperty("user"); 24 pwd=ReadProperties.getInstance() 25 .getProperty("pwd"); 26 try { 27 Class.forName(driver); 28 } catch (ClassNotFoundException e) { 29 // TODO Auto-generated catch block 30 e.printStackTrace(); 31 } 32 } 33 /** 34 * 负责连接数据库 35 * @return 连接的对象 36 * @throws SQLException 37 */ 38 public static Connection getConnection() throws SQLException{ 39 Connection conn=DriverManager 40 .getConnection(url, user, pwd); 41 42 return conn; 43 } 44 /** 45 * 关闭数据库资源,有小到大,由里到外 46 * @param conn 47 * @param stmt 48 * @param rst 49 */ 50 public static void close( 51 Connection conn, 52 Statement stmt, 53 ResultSet rst){ 54 if(rst!=null){ 55 try { 56 rst.close(); 57 } catch (SQLException e) { 58 // TODO Auto-generated catch block 59 e.printStackTrace(); 60 }finally{ 61 rst= null; 62 } 63 } 64 if(stmt !=null){ 65 try { 66 stmt.close(); 67 } catch (SQLException e) { 68 // TODO Auto-generated catch block 69 e.printStackTrace(); 70 } finally{ 71 stmt=null; 72 } 73 } 74 if(conn !=null){ 75 try { 76 conn.close(); 77 } catch (SQLException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 }finally{ 81 conn=null; 82 } 83 } 84 } 85 }
1 package com.neu.util; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.util.Properties; 6 //用户读取db.properties文件中的内容 7 //单例模式,懒汉模式 8 public class ReadProperties extends Properties { 9 private static ReadProperties read; 10 // 加载文件 11 private ReadProperties(){ 12 // 把文件转换为输入流 13 InputStream is=ReadProperties 14 .class.getResourceAsStream("/db.properties"); 15 // 加载到内存 16 try { 17 load(is); 18 } catch (IOException e) { 19 20 } 21 } 22 23 public static ReadProperties getInstance(){ 24 if(read==null){ 25 read=new ReadProperties(); 26 } 27 return read; 28 } 29 30 }
driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@10.10.2.1:1521:neu user=scott pwd=tiger
其中在eclipse中的目录结构如下图所示:
这其中箭头所指的即为几个比较关键的文件:
ojdbc14.jar是连接数据库的驱动jar包;db.properties为配置文件,其中包括连接数据库的驱动包名,连接数据库的url链接及对应数据库的数据库用户名和密码,以后如果要更换数据库的时候只需要更换驱动jar包及配置文件中对应的配置即可;
而ReadProperties.java的主要目的是将配置文件中的信息读取到创建的对象中,这样即可获得配置文件中配置的字符串变量,并将其传送给DBManager.java,
DBManager.java进行获得数据库连接对象及关闭数据库等相对简单且较为冗余的操作;
最后是BaseDao.java文件,它是未来我们操作的核心,其中的主要两个部分是findBySQL和exeuteUpdate,分别进行查找和修改两个操作;
在BaseDao.java文件中,简单一句conn=DBManager.getConnection();即可获取到数据库连接对象,public int exeuteUpdate(String sql,Object...args);可以将对应的需要操作的sql语句及其中间的问号?需要替代的参数传入,返回值为int,根据返回值来判断整个修改过程是否成功(修改操作的返回值都是返回0或者大于0的数,代表影响行,异常除外)。而
public List<HashMap<String, String>> findBySQL(String sql,Object...params)则是直接返回一个类似表的键值对结构,将查询得到的整张表作为结果返回,非常方便。以下也展示两个对其进行使用的测试代码:
1 package test; 2 3 import com.neu.dao.BaseDao; 4 5 public class TestBaseDao { 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 String id="2"; 10 String name=""; 11 String sql="delete from user_info " 12 + "where user_id=? and user_name=?"; 13 BaseDao dao=new BaseDao(); 14 int i=dao.exeuteUpdate(sql,id,name); 15 System.out.println(i); 16 } 17 }
在这里我们根据返回的i的值来判断修改操作是否成功,修改可以进行增删改三个操作;
之后我们将上边提到的三个java文件打包成jar包并发布,以后我们就可以在开发中直接使用自己的两个接口即可:
选中我们的项目文件夹,右键导出,java文件夹下JAR file文件,
选中我们需要的java文件,同时也可以加上自己的源代码,方便以后的学习使用;不附带源代码可以更加安全的发布,自己拥有自己代码的版权;
这是个属于自己的独一无二的jar包,将它导入项目中后可以完全像我们自己在eclipse中写的类一样调用即可;