JDBC就是SUN公司开发的一套通用java语言操作不同数据库的接口。
在JDBC里面Java这个公司只是提供了一套接口Connection、Statement、ResultSet,每个数据库厂商实现了这套接口。
例如MySql公司实现了:MySql驱动程序里面实现了这套接口,Java程序员只要调用实现了这些方法就可以实现对 MySql数据库的增删改查。
这里我们以MySql为例描述一下JDBC开发的基本步骤.
准备工作:
1.准备好数据库以及数据库中的数据
2.添加mysql的jar包
3.
JDBC开发步骤:
1、加载驱动Class.forName("");
2、获得连接对象Connection
3、写sql语句
4、创建Statement(一艘船)
5、执行sql语句
(1) 更新类(更改了表里面数据):delete/update/insert executeUpdate()
返回值:int,表示你影响的行数
(2)查询(没有改变表里面数据): select executeQuery()
返回值:结果集ResultSet
6、关闭连接
以下演示对student的查找,用最原始的JDBC完成
public void selectAll() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1、加载驱动Class.forName("");
Class.forName("com.mysql.jdbc.Driver");
//2、获得连接对象Connection
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2207?useUnicode=true&characterEncoding=UTF-8", "root", "1234");
//3、写sql语句
String sql = "select id,name,age,gender from student";
//4、创建Statement(一艘船)
statement = connection.createStatement();
//5、执行sql语句
// (1) 更新类(更改了表里面数据):delete/update/insert executeUpdate()
//返回值:int,表示你影响的行数
// (2)查询(没有改变表里面数据): select executeQuery()
//返回值:结果集ResultSet
resultSet = statement.executeQuery(sql);
List<Student> list = new ArrayList<>();
while (resultSet.next()) {// 如果有下一个返回true,而且指向下一个
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
String gender = resultSet.getString("gender");
Student student = new Student(id, name, age, gender);
list.add(student);
}
for (Student student : list) {
System.out.println(student);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//6、关闭连接 先打开的后关闭
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
可以看到第一步,第二步,第六步
1、加载驱动Class.forName("");
2、获得连接对象Connection
.
6、关闭连接
这三步,无论增删改查每次都要执行,而且都一样,我们可以把他们封装在一个工具类中:
package com.situ.web.util;
import java.sql.*;
public class JDBCUtil {
private final static String URL = "jdbc:mysql://localhost:3306/java2207?useUnicode=true&characterEncoding=UTF-8";
private final static String USER = "root";
private final static String PASSWORD = "123456";
// DBUtils
// 静态代码块,类加载时候只执行一次
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
return connection;
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
这样原来的代码就变成了:
private void SelectAll(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<Student> list = new ArrayList<>();
try {
connection = JDBCUtil.getConnection();
String sql = "select id,name,age,gender from student";
statement = connection.prepareStatement(sql);
System.out.println(statement);
resultSet = statement.executeQuery();
while (resultSet.next()) {// 如果有下一个返回true,而且指向下一个
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
String gender = resultSet.getString("gender");
Student student = new Student(id, name, age, gender);
list.add(student);
}
for (Student student : list) {
System.out.println(student);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.close(connection, statement, resultSet);
}
}
可以看到,这样代码就精简了很多,当我们再写增删改时也可以直接调用工具类中的方法.
细心一点就会发现,上边代码封装后,我没有用Statement,而是用的PreparedStatement
其实PreparedStatement是Statement的子类
我们来看看它们的区别:
1、语法不同:
PreparedStatement可以使用预编译的sql,只需要发送一次sql语句,后面只要发送参数即可,公用一个sql语句。
Statement只能使用静态的sql。
delete from student where id=1;
2、效率不同:
PreparedStatement使用了sql缓冲区,效率要比Statement高。
3、安全性不同:
PreparedStatement可以有效的防止sql注入,而Statement不能防止sql注入。
那么什么是SQL注入呢?
简单来说就是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击.
比如我们在登陆页面输入账号密码登陆的时候,我们会通过输入的内容,去数据库中查找是否有这个账户,以及密码是否正确,而输入的账号密码如果用Statement传输,上边说过, Statement只能使用静态的sql,如果有人恶意在再输入账号密码的地方输入SQL语句:
如本来的SQL语句应是:
SELECT * FROM users WHERE `name`='账号' AND `password`='密码';
而我们在账号中输入:zhangsan' OR 1=1 -- y
这样sql语句就变成了:
SELECT * FROM users WHERE `name`='zhangsan' OR 1=1 -- y' AND `password`='343';
可以看到 --后的都被注释掉,这样可以直接查出所有的user表的信息,即为不安全.
而 PreparedStatement会对sql语句进行预编译,然后将变量传入进行查找,就不会有这种情况发生.