之前介绍了 MySQL 数据库的基本使用,其实讲的更多的是在命令行或者图形化工具里面使用,而我们以后主要是写 Java 代码,因此也要学会使用 Java 来操作数据库,不过在实际开发中我们需要处理最多的还是数据表之中的记录,因此使用 Java 来对数据表之中的记录来进行增删改查也就十分重要了。
1.简介
这里先说一下 JDBC 是什么,它的英文全称是 Java DataBase Connectivity,翻译成中文就是 Java数据库连接,是一种用来提供执行数据库 SQL 语句的 Java API,它里面包含的就是由 Java 语言编写的类和接口,Java 语言主要提供接口,而具体的实现类则是由各个数据库厂商去实现的,这样做的目的就是为了保持 JDBC 只提供一种标准,而不会为各个数据库编写实际的类,这样做的优点在哪里呢?第一,各个数据库的具体实现肯定是他们各个厂商最为清楚的,而他们也知道怎样将性能控制地最好,第二,由于 JDBC 只是提供了一个借口,具体的实现交由各个数据库来完成,这样一个接口定义的方法在各个具体数据库上面得到的执行结果是一样的,而且在实际开发时,实际提供的是 MySQL 的驱动就调用 MySQL 数据库来完成功能,提供的是 Oracle 的驱动则调用 Oracle 数据库去完成功能,这样就能保证程序的可移植性。
2.JDBC开发的基本步骤
JDBC 的开发一般分为如下几个步骤:
1.加载驱动.
2.获得连接(Connection).
获得语句(Statement)对象
3.执行SQL
4.释放资源.
2.1 加载驱动
开发中我们一般使用如下语句来加载驱动
Class.forName("com.mysql.jdbc.Driver");
上面的语句就是用于加载 MySQL 数据库驱动的,只有加载了驱动之后才能使用 Java 操作 MySQL 数据库,当然要想使用 Oracle 数据库的话,那就要加入 Oracle 数据库的驱动了。
2.2 获得连接对象
加载驱动之后就能够使用驱动管理器获得连接对象了
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
上面的语句其实是 DriverManager 在调用 getConnection(String url,String user,String password) 方法,只要指定连接的路径、用户名以及密码就能够连接到数据库了。
获得到连接之后就可以利用连接对象获得语句对象了,语句对象便是用来执行 SQL 语句的。
Statement statement = conn.createStatement();
2.3 执行SQL语句
上面的语句便是利用连接对象获得语句对象了,下面就能使用语句对象执行我们编写的 SQL 语句了。
String sql = "select * from student;";
ResultSet rs = statement.executeQuery(sql);
上面执行 SQL 的时候因为是执行的查询语句所以才会产生结果集,如果是执行增加、修改以及删除操作就不会产生结果集。
2.4 释放资源
在使用 JDBC 完成预定的操作数据库任务之后,我们需要释放掉相应的资源,以便其它需要访问数据库的程序能够更好的运行,其中需要释放的资源主要就是 ResultSet 对象、Statement 对象以及 Connection 对象,一般资源的释放都是放在 finally 子句之中的,就是不管程序执行顺利还是发生异常都会释放资源,直接写代码吧。
finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
在调用了相关对象的 close() 方法之后,仍然将该对象置为 null ,这样是为了 Java 中的垃圾回收器能尽快回收该对象。
2.5 相关对象介绍
DriverManager:驱动管理对象,它的作用主要有两个,一个是注册驱动,另一个则是获取连接,如果使用 DriverManager 来加载驱动的话,那相应的语句应该是这样的:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
不过为什么我们一般没有使用这种方式注册驱动呢?这是为什么呢?其实看一下 Driver 这个类的源码就知道了。
package com.mysql.jdbc;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
如果使用上面那样的语句注册驱动的话,同样会使用到 com.mysql.jdbc.Driver 这个类,不过因为这个类中的静态代码块同样会执行那个方法,因此就会相当于将方法调用两次,也就是注册两次驱动,而如果使用加载 Driver 这个类的字节码文件这种方式的话,同样也可以调用注册驱动那个方法,而且只会一次,因此完全可以达到效果。
Connection:数据库连接对象,它的作用也主要是两个,第一个就是创建执行 SQL 语句的 Statement 对象,第二个就是事务管理了。关于使用 Connection 对象创建执行 SQL 语句的 Statement 对象,主要是和下面的几个方法相关:
createStatement():创建执行SQL的Statement对象
prepareStatement():创建防止SQL注入攻击的prepareStatement对象,这个对象所实现的接口PreparedStatement是上面Statement接口的子接口
关于 Connection 对象的第二个作用事务管理,使用 Connection 对象来控制事务管理最关键的部分就是关闭自动提交功能,然后手动来控制事务的提交和回滚,相关的方法如下:
void setAutoCommit(boolean autoCommit):设置自动提交,要想管理事务,则应该传入参数false
void commit():提交事务功能
void rollback():回滚事务的功能
通过调用 Connection 对象上面的这三个方法就可以控制事务了。
Statement:执行 SQL 的语句对象,它的作用同样也是两个,第一个便是执行 SQL 语句了,第二个便是进行批处理了,使用 Statement 对象执行 SQL 语句是最常见的操作了,和这种操作相关的方法如下:
ResultSet executeQuery(String sql):这个方法用来执行查询语句,并根据查询的结果返回结果集
int executeUpdate(String sql):这个方法用来执行增加、修改和删除功能的语句,返回的结果是这条语句影响的记录数(也是数据表中的行数)
boolean execute(String sql):这个方法可以用来执行上面两个方法执行的所有类型 SQl 语句,也就是说增删改查语句都可以执行,这个方法的返回值是一个布尔类型的值,也就是根据这个值来判断我们执行的是什么类型的语句,如果返回的是 true,则表示执行语句之后有 ResultSet 对象,可以使用 getResultSet() 方法来获取,这就说明我们执行的是一个查询语句;如果返回的是 false ,则可以使用 getUpdateCount() 方法获取一个数值,这个便是执行的语句影响的记录数,也就说明执行的SQL语句是增加、修改或删除类型的,其实当执行查询语句得到的是结果集时,使用 getUpdateCount() 方法会返回 -1.
使用 Statement 对象进行批处理的话,就是将多条 SQl 语句添加到 Statement 对象命令列表中,然后再一次性全部执行,涉及的具体的方法如下:
void addBatch(String sql):将指定的SQL语句添加到命令列表之中
void clearBatch():清空当前对象的命令列表
int[] executeBatch():一次性执行命令列表中所有的SQL语句
ResultSet:结果集对象,是执行查询语句时获得的结果,用于存放查询得到的记录,我们在获得到结果集之后一般都会对结果集进行遍历,可以将结果集中的记录信息打印输出或者使用每一行记录的信息来封装相应的对象,所以,最重要的还是如何遍历结果集中的数据信息。相关的方法如下:
boolean next():该方法是用来遍历一行一行记录的,第一次调用该方法使第一行成为当前行,第二次则使第二行成为当前行,如果新的当前行有效,则返回true,否则就返回false
上面的这个方法是用来获取各个记录行的,下面将介绍的方法则用于如何获取一个记录中的各个字段值。
int getInt(int columnIndex)
int getInt(String columnLabel)
上面这两个方法都可以用于获得一条记录中某个 int 类型数据的字段值,第一个方法传入的参数是该字段在这行记录中的索引值,以 1 开始,第二个方法传入的参数是该字段的字段名称,两个方法都可以取得相应的字段值,不过最好还是采用传入字段名称的方法,则是因为如果 SQL 语句稍有差异,那么很可能各字段的索引就会发生变化,因此采用字段名称是比较好的方法。
当然在一行记录中会有各种不同类型的数据,因此 ResultSet 对象也提供了相应的多种方法用来获取相应的字段值,其中非常常见的还有:
String getString(int columnIndex)
String getString(String columnLabel)
Object getObject(int columnIndex)
Object getObject(String columnLabel)
当然 float 和 double 类型的数据也都有对应的方法来获取字段值。
使用上面介绍的方法,就可以写一个简单的遍历数据集的程序了。
String sql = "select * from student;";
rs = statement.executeQuery(sql);
while (rs.next()) {
System.out.print(rs.getInt("id") + " ");
System.out.print(rs.getString("name") + " ");
System.out.print(rs.getInt("chinese") + " ");
System.out.print(rs.getInt("english") + " ");
System.out.print(rs.getInt("math") + " ");
System.out.println();
}
这样就能够遍历结果集并能打印出相应的记录信息了,如果查询出的结果只有一条的话那就没必要用 while 了,而直接使用 if 就好了。
3.使用JDBC进行增删改查操作
在使用 Java 对数据库进行操作的过程中,使用的最多的还是对记录的增删改查,因此下面将介绍一下使用 JDBC 来进行记录的增删改查操作。
3.1 增加记录
其实不管使用 JDBC 开发什么功能,都会有一个基本的步骤,加载驱动、获得连接对象以及获得语句对象,执行 SQl 语句,处理结果集,以及最后释放掉资源。
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
statement = conn.createStatement();
String sql = "insert into student values(null,'kobe',80,90,70);";
int num = statement.executeUpdate(sql);
if(num>0) {
System.out.println("用户添加成功!");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn=null;
}
if(statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement=null;
}
}
}
3.2 删除记录
删除记录只需要根据给定的条件确定记录,然后删除删除掉这些记录就好了。
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
statement = conn.createStatement();
String sql = "delete from student where id = 8;";
int num = statement.executeUpdate(sql);
if (num > 0) {
System.out.println("用户删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
}
}
3.3 修改记录
修改记录中各个需要修改的字段的值,首先给定条件确定要修改的记录,然后修改选定记录中各字段的值。
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
statement = conn.createStatement();
String sql = "update student set chinese = 90 where name = 'kobe';";
int num = statement.executeUpdate(sql);
if (num > 0) {
System.out.println("用户修改成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
}
}
3.4 查询记录
这个是实际开发中使用的最多的,大部分的应用都会涉及到查询,根据给定的查询条件,查询出相关记录的结果集,然后进行遍历结果集的操作。
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
statement = conn.createStatement();
String sql = "select * from student;";
rs = statement.executeQuery(sql);
while (rs.next()) {
System.out.print(rs.getInt("id") + " ");
System.out.print(rs.getString("name") + " ");
System.out.print(rs.getInt("chinese") + " ");
System.out.print(rs.getInt("english") + " ");
System.out.print(rs.getInt("math") + " ");
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
4.工具类的抽取
从上面增删改查的例子程序中就可以看出,每段程序之中都会有加载驱动、获得连接以及释放资源这样的相同操作,甚至每次加载的配置信息都完全是一样的,如果完全这样写的话,肯定是不好的,因为以后维护不方便,一个配置信息的修改则要修改所有包含该配置信息的代码块,因此我们需要抽取相关的工具类,以便让开发维护更加简单。
首先是配置信息,我们可以将数据库的连接地址 url 、用户名以及密码写到一个文本文件当中,然后当程序运行时直接加载该文本文件中的内容,这样就只需要加载一次配置信息了,而且当相关配置信息需要修改时,只需要修改该文本文件就好了,而不需要改动程序,这样维护起来也十分方便。
同时,驱动的加载、连接对象的获取,还有相关资源的释放这些在每个程序段中都一样的操作也可以提取出方法,这样在需要使用相关功能的时候就只需要调用相关方法就好了,而不需要每次都写那么一段,维护起来也不方便。
相关的配置文件(db.properties):
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/test3
user = root
password = 123456
抽取的工具类(JDBCUtils):
public class JDBCUtils {
private static final String driverClassName;
private static final String url;
private static final String user;
private static final String password;
static {
Properties prop = new Properties();
try {
prop.load(new FileInputStream(new File(
"src/day08/jdbc/db.properties")));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
driverClassName = prop.getProperty("driverClassName");
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
}
/**
* 加载数据库驱动
*/
public static void loadDriver() {
try {
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
*/
public static Connection getConnection() {
Connection conn = null;
try {
loadDriver();
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static void release(Statement statement, Connection conn) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs, Statement statement,
Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
5.SQL注入漏洞
使用 Statement 语句对象执行 SQL语句的时候,在验证用户登录的时候会碰到一种情况,那就是用户不按照正常的逻辑输入用户名和密码,而是会包含一些对于 SQL 来说特殊的字符,比如,后台验证登录的 SQL 语句是这样的:
String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";
其中的第二个 username 以及 password 是用户在前台输入的用户名以及密码,拼接到 SQL 之中后就可以验证具体的用户名和密码了。
如果用户在登录的时候输入一般的用户名和密码,那是完全没有问题的,但是如果用户在输入时不按照一般的逻辑输入,那就可能会出问题了,比如下面两种情况:
1.用户名为 aaa' or '1=1 密码随意
2.用户名为 aaa' -- 密码随意
如果用户的输入是像上面这两种情况,那么在只知道用户名的情况下也是可以登录成功的,这样就完全得不到校验的效果了,用户输入第一种情况时,后台根据前台传入的数据拼接而成的 SQl 语句应该是:
select * from user where username = 'aaa' or '1=1' and password = 'xxx'
很明显可以看出的是,上面的 SQL 语句中只要保证用户名是正确的,就能通过登录验证,但是在实际生活中,用户名一般都是以明文显示在网页之上的,因此获取十分简单,所以这样就会泄露账户信息。
根据用户输入的第二种情况,后台的 SQL 语句会像下面这个样子:
String sql = "select * from user where username = 'aaa' -- ' and password = 'xxx'
上面语句的关键在于 SQl 中包含 -- 这样的特殊字符串,而这个字符串在 SQL 语句中的作用是注释,因此程序在运行时会忽略掉 -- 后面的所有代码,这样 SQL 语句就会变成下面这样了:
String sql = "select * from user where username = 'aaa'
这个语句验证的效果就和上面的那一句是一样的了,都只会验证用户名是否正确,而用户名都是明文显示在网页上的,因此用户在使用时是十分不安全的。
下面的一节将介绍如何解决这个问题。
6.PreparedStatement语句对象
要想解决上面的 SQL 注入问题,可以使用本节将会介绍的 PreparedStatement 语句对象,上面之所以会出现 SQl 注入问题,就是因为在后台处理传入参数的时候,会将传入的参数直接拼接到 SQL 语句当中,因此如果传入的参数中存在 SQL 关键字的话,就很可能会改变我们原来使用 SQL 的意图,而 PreparedStatement 语句对象采用的是预编译的方式,在要传值的地方先使用 ? 占位,预先固定下来 SQL 语句的格式,这样即使传入的参数中存在 SQL 的关键字,也只会将它们看做一般的字符串。
6.1 使用PreparedStatement增加记录
其实使用 PreparedStatement 和原来使用 Statement 操作数据表中的记录是差不多的,只是会先使用 ? 去占位,然后再将各个值赋到相应的地方,,改变的地方直接从代码中就可以看出来。
public class PreparedStatementAdd {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstm = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into student values(null,?,?,?,?);";
pstm = conn.prepareStatement(sql);
pstm.setString(1, "kobe");
pstm.setInt(2, 87);
pstm.setInt(3, 94);
pstm.setInt(4, 87);
int num = pstm.executeUpdate();
if(num>0) {
System.out.println("用户增加成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(pstm, conn);
}
}
}
6.2 使用PreparedStatement删除记录
删除记录也是一样,因为删除记录主要是根据 id 主键来进行的,因此先使用一个 ? 占住需要传入 id 值的位置,然后再对相应的地方赋值,最后使用语句对象执行 SQL 语句就可以达到目的。
public class PreparedStatementDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstm = null;
try {
conn = JDBCUtils.getConnection();
String sql = "delete from student where id = ?;";
pstm = conn.prepareStatement(sql);
pstm.setInt(1, 9);
int num = pstm.executeUpdate();
if (num > 0) {
System.out.println("用户删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(pstm, conn);
}
}
}
6.3 使用PreparedStatement修改记录
修改记录也是一样,关键在于确定哪些值需要修改,然后使用 ? 去占住相应的位置,接着使用具体的值去赋值,最后执行 SQL 语句以达到效果。
public class PreparedStatementUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstm = null;
try {
conn = JDBCUtils.getConnection();
String sql = "update student set chinese = ? where name = 'kobe'" ;
pstm = conn.prepareStatement(sql);
pstm.setInt(1, 60);
int num = pstm.executeUpdate();
if(num>0) {
System.out.println("修改用户成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(pstm, conn);
}
}
}
6.4 使用PreparedStatement查询记录
查询记录主要就是将查询条件在 SQL 中所处的位置首先使用 ? 确定下来,然后赋予相应的位置具体的查询条件,执行 SQL 语句以得到结果。当然如果是查询所有数据,没有筛选条件也是可以的。
public class PreparedStatementSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select * from student;";
pstm = conn.prepareStatement(sql);
rs = pstm.executeQuery();
while (rs.next()) {
System.out.print(rs.getInt("id") + " ");
System.out.print(rs.getString("name") + " ");
System.out.print(rs.getString("chinese") + " ");
System.out.print(rs.getString("english") + " ");
System.out.print(rs.getString("math") + " ");
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, pstm, conn);
}
}
}
其实,使用 PreparedStatement 语句对象和 Statement 对象相比只是稍有变化,注意一下就好了,而且 PreparedStatement 比 Statement 更加安全,因此使用的也更多。
7.批处理
说的简单点,批处理就是一次执行多条 SQL 语句,可以包含各种类型的 SQL 语句,比如创建数据表,插入数据到数据表中,当然也包含插入很多条数据到某张表中。
下面看一下具体的例子:
public class BatchDeal {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
conn = JDBCUtils.getConnection();
statement = conn.createStatement();
String sql = "create database test3";
String sql2 = "use test3";
String sql3 = "create table student(id int primary key auto_increment,"
+ "name varchar(10) ,"
+ "sex varchar(3),"
+ "age int)";
String sql4 = "insert into student values(null,'kobe','男',17)";
String sql5 = "insert into student values(null,'james','男',18)";
String sql6 = "insert into student values(null,'koko','女',17)";
String sql7 = "insert into student values(null,'gogo','女',19)";
statement.addBatch(sql);
statement.addBatch(sql2);
statement.addBatch(sql3);
statement.addBatch(sql4);
statement.addBatch(sql5);
statement.addBatch(sql6);
statement.addBatch(sql7);
statement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(statement, conn);
}
}
}
上面的这个例子就是创建数据库以及创建数据表,并往其中添加数据的例子,使用批处理就可以像这样将多条 SQL 添加到一个命令列表之中,然后再一次性执行全部的 SQL 语句。
public class BatchDeal2 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Connection conn = null;
PreparedStatement statement = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into student values(null,'Kobe','男',?)";
statement = conn.prepareStatement(sql);
for (int i = 0; i <= 10000; i++) {
statement.setInt(1, i);
statement.addBatch();
if (i % 1000 == 0) {
statement.executeBatch();
statement.clearBatch();
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.release(statement, conn);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
上面的这个例子就是增加一万行数据记录,不过在每次积累到一千行的时候都会先执行一次,并且清空掉命令列表,例子中还计算了运行所需要的时间。
8.总结
其实使用 JDBC 对数据库进行操作,最重要的还是掌握基本的开发流程,比如加载驱动、获得连接、获得语句对象、执行语句以及获得执行结果,然后最后释放掉各种数据库资源,只要把握住了这个开发流程其它的到底使用哪个语句对象都好说了,语句对象主要是 PreparedStatement 和 Statement 这两个,使用 PreparedStatement 预编译的方式进行开发相对来说更加安全,最后批处理的话,就是先将多条 SQL 语句添加到一个命令列表之中,然后一次性执行掉所有的 SQL 语句,这就是批处理最基本的概念。