创建一个获取 Connection 对象和关闭资源的工具类

在对数据库进行 CRUD 操作的时候,每一个操作都需要获取 Connection 对象,所以我们就可以把获取 Connection 对象的过程抽离到一个工具类当中,下面是具体代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public final class JdbcUtil
{
private JdbcUtil()
{
}

private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL";
private static String user = "scott";
private static String password = "tiger";

static
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch (ClassNotFoundException e)
{
throw new ExceptionInInitializerError("加载驱动类出错!!");
}
}

public static Connection getConnection() throws Exception
{
Connection connection = null;
connection = DriverManager.getConnection(url, user, password);
return connection;
}

public static void close(Connection connection, ResultSet rs, Statement statement)
{
if (rs != null)
{
try
{
rs.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
if (statement != null)
{
try
{
statement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
if (connection != null)
{
try
{
connection.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
}

}

}
}

我把 url,username,password 放在了类中,也可以将这些配置信息放入到配置文件中,一般的做法是放入到配置文件当中,此处就是简单些。将加载驱动类的方法放入到 static 静态块当中,当调用 getConnection 静态方法的时候,static 静态块会先执行,就会先加载驱动类。Close 方法就是关闭 Statement, Connection ,ResultSet 对象的资源。

使用 Statement 和 ResultSet 进行简单 CRUD 操作

首先看一下 Statement 接口的文档说明:

用于执行静态 SQL 语句并返回它所生成结果的对象。

在默认情况下,同一时间每个 Statement 对象在只能打开一个 ResultSet 对象。因此,如果读取一个 ResultSet 对象与读取另一个交叉,则这两个对象必须是由不同的 Statement 对象生成的。如果存在某个语句的打开的当前 ResultSet 对象,则 Statement 接口中的所有执行方法都会隐式关闭它。

Statement 的主要作用就是执行 SQL 语句并且返回它所生产的结果对象。Statement 对象是通过 Connection 对象进行获取的,通过
Connection. createStatement() 方法获取 Statement 对象。通过执行 Statement 对象的 executeQuery() 方法进行查询 SQL,该语句返回单个 ResultSet 对象。

下面是简单的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void read(String id, String password)
{
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try
{
connection = JdbcUtil.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("select id, name from student where id = '" + id + "' and password = '" + password + "'");

while (resultSet.next())
{
System.out.println("id = " + resultSet.getInt("id") + ", name = " + resultSet.getString("name"));
}
}
catch(SQLException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
JdbcUtil.close(connection, resultSet, statement);
}
}

模拟了一个简单的查询用户信息的 sql,传入 id 和 password 对数据库进行查询,然后输出。Sql 语句是通过传入的值拼接而成,所以这样就很容易被 SQL 注入。当我传入的 password 值为 ‘ or 1 = 1 or ‘ 的时候打印出来 sql 语句如下:

1
select id, name from student where id = 'rcx' and password = '' or 1 = 1 or ''

因此就可以查询到用户的信息,引起的不安全的漏洞。一般带参数的查询都需要使用 PreparedStatement 对象。

使用 PreparedStatement 和 ResultSet 进行简单 CRUD 操作

首先看一下 PreparedStatement 接口,它继承于 Statement 接口。表示预编译的 SQL 语句的对象。SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。 通过调用 Connection 对象的 prepareStatement(sql) 方法来获取。

PreparedStatement 对象的,传入的参数是预编译的 sql 语句,带参数部分通过?代替。上面的例子通过 PreparedStatement 进行查询代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public void read1(String id, String password)
{
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try
{
connection = JdbcUtil.getConnection();
String sql = "select id, name from student where id = ? and password = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, id);
statement.setString(2, password);

resultSet = statement.executeQuery();

while (resultSet.next())
{
System.out.println("id = " + resultSet.getInt("id") + ", name = " + resultSet.getString("name"));
}
}
catch(SQLException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
JdbcUtil.close(connection, resultSet, statement);
}
}

由于 PreparedStatement 的预处理 sql,可以有效的防止 sql 注入的问题,同时还可以提高一些效率。

注意:

1
resultSet = statement.executeQuery();

由于 PreparedStatement 继承于 Statement,所以也有 executeQuery(sql) 带参数的方法,如果这样写的话那么执行的就是父接口当中的方法了,不会对 sql 进行预处理了。

一些其他的方法

由于查询是调用 executeQuery() 方法的,在插入更新与删除操作是调用 executeUpdate(Sql) 方法,执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。

ResultSet 对象的 next() 方法:将光标从当前位置向前移一 行。ResultSet 光标最初位于第一行之前;第一次调用 next 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。

完整的CRUD代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class CRUD {

public static void main(String[] args) throws SQLException {
// create();
read();
// update();
// delete();
}

static void delete() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();

String sql = "delete from user where id>4";

// 4.执行语句
int i = st.executeUpdate(sql);

System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}

static void update() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();

String sql = "update user set money=money+10 ";

// 4.执行语句
int i = st.executeUpdate(sql);

System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}

static void create() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();

String sql = "insert into user(name,birthday, money) values ('name1', '1987-01-01', 400) ";

// 4.执行语句
int i = st.executeUpdate(sql);

System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}

static void read() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();

// 4.执行语句
rs = st.executeQuery("select id, name, money, birthday from user");

// 5.处理结果
while (rs.next()) {
System.out.println(rs.getObject("id") + "\t"
+ rs.getObject("name") + "\t"
+ rs.getObject("birthday") + "\t"
+ rs.getObject("money"));
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}

}

—EOF—