JDBC--数据库链接及相关方法的封装
使用的是MySQL数据库,首先导入驱动类,然后根据数据库URL和用户名密码获得数据的链接。由于使用的是MySQL数据库,它的URL一般为,jdbc:mysql://主机地址:端口号/库名。
下面是封装的具体类,用到了泛型和反射,不过还存在些问题,就是对使用的泛型对象有些限制,只能用于泛型类对象属性名与数据库表中列名相同的对象,而且初始化对象的方法必须为set+属性名的方法。
1 public class Consql { 2 private static Consql consql=null;//单例设计模式 3 private Connection conn=null;//数据库链接 4 private final String url;//数据库url 5 private final String username;//数据库用户名 6 private final String password;//数据库密码 7 //驱动类的加载 8 static{//以静态代码块的形式加载驱动类,静态代码块只在类加载的时候执行一次 9 try { 10 Class.forName("com.mysql.jdbc.Driver"); 11 } catch (ClassNotFoundException e) { 12 e.printStackTrace(); 13 } 14 } 15 //构造函数 16 private Consql(String url,String username,String password) throws SQLException{ 17 this.url = url; 18 this.username = username; 19 this.password = password; 20 open();//创建连接 21 } 22 private Connection open() throws SQLException 23 { 24 try {//驱动器获取数据库链接 25 conn=DriverManager.getConnection(url, username, password); 26 } catch (SQLException e) { 27 // TODO Auto-generated catch block 28 //e.printStackTrace(); 29 throw e; 30 } 31 return conn; 32 } 33 /** 34 * 带限制条件查找 35 * @param sql 带占位符?的sql语句 36 * @param t 返回相关类型对象的类(T.class) 37 * @param params 替换占位符的数据,为动态数组,不写的话数组长度为0 38 * @return ArrayList<T> 39 * @throws SQLException 40 */ 41 public <T> ArrayList<T> select(String sql,Class<T> t,Object...params) throws SQLException 42 {//获取T类所有public方法 43 Method[] declaredMethods = t.getDeclaredMethods(); 44 //创建一个盛放该类型对象集合 45 ArrayList<T> arrayList=new ArrayList<>(); 46 try (PreparedStatement pStatement=conn.prepareStatement(sql);) 47 { 48 for(int i=0;i<params.length;i++) 49 { 50 pStatement.setObject(i+1, params[i]); 51 } 52 try(ResultSet rSet=pStatement.executeQuery();) 53 { 54 ResultSetMetaData rData=rSet.getMetaData(); 55 //获取查询到结果表的列数 56 int columnCount = rData.getColumnCount(); 57 while (rSet.next()) { 58 T a=t.newInstance();//创建泛型类实例 59 for(int i=0;i<columnCount;i++) 60 {//获得方数组里的set方法,这里造成了局限性,只能数据库表列名与对象名一致,且只能是set方法 61 String aString="set"+rData.getColumnName(i+1); 62 for (Method method : declaredMethods) { 63 if(method.getParameterCount()==1&&method.getReturnType().toString().equals("void")&&method.getName().equalsIgnoreCase(aString)) 64 {//这里存在问题,前两个判断条件基本没用,主要是最初不想用上面拼串的方式来判断是不是调用该参数的方法 65 method.setAccessible(true); 66 //利用反射调用该方法 67 method.invoke(a, rSet.getObject(i+1)); 68 break; 69 } 70 } 71 } 72 arrayList.add(a); 73 } 74 } catch (InstantiationException e) { 75 // TODO Auto-generated catch block 76 e.printStackTrace(); 77 } catch (IllegalAccessException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } catch (IllegalArgumentException e) { 81 // TODO Auto-generated catch block 82 e.printStackTrace(); 83 } catch (InvocationTargetException e) { 84 // TODO Auto-generated catch block 85 e.printStackTrace(); 86 } 87 } catch (SQLException e) { 88 // TODO Auto-generated catch block 89 throw e; 90 } 91 return arrayList; 92 } 93 /** 94 * 数据插入 95 * @param sql 带占位符?的sql语句 96 * @param params 替换占位符的数据,动态数组 97 * @throws SQLException 98 */ 99 public void insert(String sql,Object...params) throws SQLException 100 { 101 try(PreparedStatement pStatement=conn.prepareStatement(sql);) { 102 103 for(int i=0;i<params.length;i++) 104 { 105 pStatement.setObject(i+1, params[i]); 106 } 107 pStatement.executeUpdate(); 108 } catch (SQLException e) { 109 // TODO Auto-generated catch block 110 throw e; 111 } 112 } 113 /** 114 * 数据更新 115 * @param sql 带占位符?的sql语句 116 * @param params 替换占位符的数据,动态数组 117 * @throws SQLException 118 */ 119 public void update(String sql,Object...params) throws SQLException 120 { 121 try(PreparedStatement pStatement=conn.prepareStatement(sql);) { 122 123 for(int i=0;i<params.length;i++) 124 { 125 pStatement.setObject(i+1, params[i]); 126 } 127 pStatement.executeUpdate(); 128 } catch (SQLException e) { 129 // TODO Auto-generated catch block 130 throw e; 131 } 132 } 133 /** 134 * 带限制条件删除 135 * @param sql 带占位符?的sql语句 136 * @param params 替换占位符的数据,动态数组,不写这个参数,数组长度就为0 137 * @throws SQLException 138 */ 139 public void delete(String sql,Object...params) throws SQLException 140 { 141 try(PreparedStatement pStatement=conn.prepareStatement(sql);) { 142 143 for(int i=0;i<params.length;i++) 144 { 145 pStatement.setObject(i+1, params[i]); 146 } 147 pStatement.executeUpdate(); 148 } catch (SQLException e) { 149 // TODO Auto-generated catch block 150 throw e; 151 } 152 } 153 /** 154 * 删除全部,不带有限制,实际上与上一个方法重复了。 155 * @param sql 156 * @throws SQLException 157 */ 158 public void deleteall(String sql) throws SQLException 159 { 160 try(PreparedStatement pStatement=conn.prepareStatement(sql);) { 161 pStatement.executeUpdate(); 162 } catch (SQLException e) { 163 // TODO Auto-generated catch block 164 throw e; 165 } 166 } 167 /** 168 * 无限制条件查找,实际上与上一个查询的方法重复了 169 * @param sql 170 * @param t 泛型类T.class 171 * @return ArrayList<T> 172 * @throws SQLException 173 */ 174 public <T> ArrayList<T> select(String sql,Class<T> t) throws SQLException 175 { 176 Method[] declaredMethods = t.getDeclaredMethods(); 177 ArrayList<T> arrayList=new ArrayList<>(); 178 try (PreparedStatement pStatement=conn.prepareStatement(sql);) 179 { 180 try(ResultSet rSet=pStatement.executeQuery();) 181 { 182 ResultSetMetaData rData=rSet.getMetaData(); 183 int columnCount = rData.getColumnCount(); 184 while (rSet.next()) { 185 T a=t.newInstance(); 186 for(int i=0;i<columnCount;i++) 187 { 188 String aString="set"+rData.getColumnName(i+1); 189 for (Method method : declaredMethods) { 190 if(method.getName().equalsIgnoreCase(aString)) 191 { 192 method.setAccessible(true); 193 method.invoke(a, rSet.getObject(i+1)); 194 break; 195 } 196 } 197 } 198 arrayList.add(a); 199 } 200 } catch (InstantiationException e) { 201 // TODO Auto-generated catch block 202 e.printStackTrace(); 203 } catch (IllegalAccessException e) { 204 // TODO Auto-generated catch block 205 e.printStackTrace(); 206 } catch (IllegalArgumentException e) { 207 // TODO Auto-generated catch block 208 e.printStackTrace(); 209 } catch (InvocationTargetException e) { 210 // TODO Auto-generated catch block 211 e.printStackTrace(); 212 } 213 } catch (SQLException e) { 214 // TODO Auto-generated catch block 215 throw e; 216 } 217 return arrayList; 218 } 219 /** 220 * 返回表中数据行数 221 * @param tableName 数据库表名 222 * @return 行数 223 * @throws SQLException 224 */ 225 public int count(String tableName) throws SQLException 226 { 227 String sql="select count(*) from "+tableName; 228 try(PreparedStatement pStatement=conn.prepareStatement(sql); 229 ResultSet rsSet=pStatement.executeQuery(); ) 230 { 231 if(rsSet.next()) 232 { 233 return rsSet.getInt(1); 234 } 235 } catch (SQLException e) { 236 // TODO Auto-generated catch block 237 throw e; 238 } 239 return 0; 240 } 241 /** 242 * 判断数据是否存在 243 * @param sql 带占位符?的sql语句 244 * @param params 替换占位符的数据,动态数组 245 * @return boolean 246 * @throws SQLException 247 */ 248 public boolean isExist(String sql,Object...params) throws SQLException 249 { 250 try(PreparedStatement pStatement=conn.prepareStatement(sql);) 251 { 252 for(int i=0;i<params.length;i++) 253 { 254 pStatement.setObject(i+1, params[i]); 255 } 256 try(ResultSet rsSet=pStatement.executeQuery();) { 257 if(rsSet.next()) 258 { 259 return true; 260 } 261 } finally { 262 263 } 264 } catch (SQLException e) { 265 // TODO Auto-generated catch block 266 throw e; 267 } 268 return false; 269 } 270 /** 271 * 创建实例 272 * @param url 数据库url 273 * @param username 用户名 274 * @param password 密码 275 * @return consql对象 276 * @throws SQLException 277 */ 278 public static Consql getnewInstance(String url,String username,String password) throws SQLException 279 { 280 if(consql==null) 281 consql=new Consql(url, username, password); 282 return consql; 283 } 284 //垃圾回收,貌似并不能达到析构函数的效果 285 protected void finalize() throws Throwable 286 { 287 if(conn!=null) 288 { 289 conn.close(); 290 } 291 super.finalize(); 292 } 293 }
本来想通过返回值类型,参数列表来确定该属性初始化方法的,然而可能是目前学到的还是太少,只学了三周,所以并没有实现,感觉这个方法还是很low,以后还要继续完善。本来看到网上有用beanUtils包,利用map将查询的一列存起来,直接转化成该对象的,但是就是想试试新学到的反射。而且最后的垃圾回收器并不能如同C++的析构函数一样,所以关闭数据库链接的地方也需要改善。
实际上两个删除的方法和两个查询的方法是重复的,可变的参数列表,当无参数时,数组长度就为0,因此造成了两个方法的包含关系。
人生如水,不争高山,自然愈下,三年又三年。——struggle!