之前一直用statement开发,statement对象作为将SQL语句发送到数据库的工具,非常的好用,我一般都是定义一个DBManager,先封装了statement对象的创建,和返回结果集的函数:
public Statement getStatement() {
Connection connection = null;
Statement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
//Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/pinshan?useUnicode=true&characterEncoding=utf8&useSSL=true", "root", "root")
connection = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/data?useUnicode=true&characterEncoding=utf8&useSSL=true", "root", "root");
stmt = connection.createStatement();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stmt;
}
public ResultSet query(String sql) {
ResultSet rst = null;
Statement stmt = getStatement();
System.out.println("stmt = " + stmt);
try {
rst = stmt.executeQuery(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rst;
}
这两天看书,书上强烈的介绍了preparedstatement,主要有三个好处:
1、预编译SQL语句,性能更好。
2、无须拼接SQL语句,不麻烦,不易出错,有利于编程和后期维护。
3、可以防止sql注入,安全性更好。
简直直击我心!!!
我总是担心sql注入,怕谁给我把用户信息删了,或者黑我服务器什么的。前端的监控能力是有限的,sql注入难以幸免。 所以有了这个preparedstament,我是无论何如要试试看的。
首先是把DBManager的方法换了:
这里注意要返回一个PreparedStatement类型。
public PreparedStatement getPreStatement(String sql) {
Connection connection = null;
PreparedStatement ps=null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/data?useUnicode=true&characterEncoding=utf8&useSSL=true", "root", "root");
ps=connection.prepareStatement(sql);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ps;
}
然后就是把之前的拼接字段全部改成“?”占位符,然后调用PreparedStatement的方法去填充它。 这里不满意的是,居然不能一起填充了,要位置和内容一一对应,一个一个填充。开始我少填了一个,编译直接报错了,我觉得不错还挺好的,之前用statement开发,因为少写了 , 或者是 )编译不报错,测试的时候才出错,这其实是不好的。
String sqls = "update pinshan.goto shan SET shan=? where username=?" ;
preparedStatement=db.getPreStatement(sqls);
preparedStatement.setString(1,shan);
preparedStatement.setString(2,username);
preparedStatement.execute();
最后就是这个错:
Exception in thread "main" java.sql.SQLException:Can not issue data manipulation statements with executeQuery().
atcom.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
atcom.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
atcom.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
atcom.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
atcom.mysql.jdbc.StatementImpl.checkForDml(StatementImpl.java:463)
atcom.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1926)
这是preparedStatement.execute();preparedStatement.executeQuery(sql);的用法没有搞清楚的关系。
一句话,execute()的返回值是布尔类型,就是返回正确执行了没有,而executeQuery是返回查询的结果集的,需要赋给左边的结果集。
ResultSet rst=preparedStatement.executeQuery(sql);