今天上午才了解到我之前写的DBTools会导致sql注入,所以今天来升级下这个DBTools
这次我们连接数据库就不用一个方法了,直接在static里面完成
1 //创建一个静态代码块连接数据库 2 static { 3 try { 4 //导入驱动类 5 Class.forName("com.mysql.jdbc.Driver"); 6 //创建连接对象 7 conn = DriverManager.getConnection(url,user,pwd); 8 } catch (ClassNotFoundException | SQLException e) { 9 e.printStackTrace(); 10 } 11 }
这样在程序执行的时候就连接了数据库,不需要再调用一个方法了
那么先来重写查询的方法,我们原本的方法是这样的
1 //数据库查询操作 2 public static ResultSet executeQuery(String sql) throws Exception { 3 //调用连接数据库方法连接数据库 4 connetcDatabase(); 5 //创建命令行 6 stt = conn.createStatement(); 7 //执行sql语句 8 ResultSet result = stt.executeQuery(sql); 9 //返回操作结果 10 return result; 11 }
如果按照以上方式写,使用Statement对象,很容易导致SQL注入,我们就可以这样写
1 //数据库查询操作 2 public static ResultSet executeQuery(String sql) throws Exception { 3 //创建命令行 4 PreparedStatement ppt = conn.prepareStatement(sql); 5 //执行sql语句 6 ResultSet result = ppt.executeQuery(); 7 //返回操作结果 8 return result; 9 }
那使用预编译的Statement可以防止sql注入,因为这个是把值当作参数传给sql语句
也就是说我们需要传值的地方写个? 然后使用setObject等等方式来进行传值
但是这里有个问题,我们不知道会有多少个参数,那就需要可变参数来完成,然后用for循环遍历
1 //数据库查询操作 2 public static ResultSet executeQuery(String sql,Object ... objs) throws Exception { 3 //创建预编译的Statement 4 PreparedStatement ppt = conn.prepareStatement(sql); 5 //遍历传值 6 for(int i=0;i<objs.length;i++){ 7 ppt.setObject(i+1,objs[i]); 8 } 9 //执行sql语句 10 ResultSet result = ppt.executeQuery(); 11 //返回操作结果 12 return result; 13 }
但是这还有个问题,因为查询全部的话,就不需要传参数过来,那么objs为null就会报异常
那么我们需要在for的条件判断再加一个
//遍历传值 for(int i=0;objs!=null&&i<objs.length;i++){ ppt.setObject(i+1,objs[i]); }
那么这样就解决了这个问题,那么增删改的也是一样,复制过去
1 //数据库增删改操作 2 public static int executeUpdate(String sql,Object ... objs) throws Exception { 3 //创建预编译的Statement 4 PreparedStatement ppt = conn.prepareStatement(sql); 5 //遍历传值 6 for(int i=0;objs!=null&&i<objs.length;i++){ 7 ppt.setObject(i+1,objs[i]); 8 } 9 //执行sql语句 10 int line = ppt.executeUpdate(); 11 //返回操作结果 12 return line; 13 }
然后我们会发现,里面的for循环一模一样,那么我们可以把这个单独封装成一个方法
1 //获取PreparedStatement对象 2 public static PreparedStatement getPreparedStatement(String sql,Object ... objs) throws Exception { 3 //创建预编译的Statement 4 PreparedStatement ppt = conn.prepareStatement(sql); 5 //遍历传值 6 for(int i=0;objs!=null&&i<objs.length;i++){ 7 ppt.setObject(i+1,objs[i]); 8 } 9 //返回PreparedStatement对象 10 return ppt; 11 }
那么这么封装以后,我们的查询和增删改的方法就可以简短一些
然后关闭连接的方法依旧是关闭连接的方法,不变
1 //关闭数据库连接 2 public static void closeConnection() throws Exception { 3 //关闭数据库连接 4 conn.close(); 5 }
那么这个DBTools就修改完成了,但是进行测试的时候发现出了问题,进行第一次数据库操作会把数据库给关闭连接了
所以我们不能把数据库连接写在静态代码块中了,只能写一个方法了
1 //创建一个方法连接数据库 2 public static void getConnection() throws Exception { 3 //创建连接对象 4 conn = DriverManager.getConnection(url,user,pwd); 5 }
那么我们在getPreparedStatement这个方法中调用就OK了