以OOP(即面向对象编程)编写 JDBC 程序

1.JDBC工具类

将一些常用的 JDBC 方法封装成一个 JDBC 工具类, 方便管理及调用.

下面程序中的配置文件 jdbc.properties 必须在当前项目的 src 目录下.

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

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/*
* 操作 JDBC 的工具类,封装了一些常用的方法
*/
public class JDBCTools {
/**
* 获取数据库连接:
* 通过读取配置文件,根据配置信息从数据库服务器获取一个连接
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception {
InputStream is = JDBCTools.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pro = new Properties();
pro.load(is);
String url = pro.getProperty("jdbc");
String user = pro.getProperty("user");
String password = pro.getProperty("password");
Class.forName(pro.getProperty("driver"));
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* 通用的执行SQL更新语句,包括: Insert Delete Update语句, 不能执行select语句
* @param sql
*/
public static void update(String sql) {
Connection conn = null;
Statement state = null;
try {
conn = JDBCTools.getConnection();
state = conn.createStatement();
state.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCTools.release(null,state, conn);
}
}
/**
* 关闭 ResultSet 和 Statement 和 Connection
* @param rs
* @param state
* @param conn
*/
public static void release(ResultSet rs,Statement state,Connection conn) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(state != null) {
try {
state.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

2.操作Student数据表中的数据

利用 Java 的对象操作数据表中的记录, 这里的 Java 对象之后会有个专业名词: JavaBean

处理表的记录时, 不再一个字段一个字段的处理, 而是把它们封装成一个对象, 统一处理.

可以称为 O-R映射 即 对象与关系(也可以说数据表)之间的映射, 对象的属性与数据表的字段一一对应.

A.DB中的Student表

id name email birth
1 Bob bob@qq.com 1997-01-01
2 Jane jane@qq.com 1999-09-09
3 Jhon jhon@qq.com 2000-10-01

B.Java中的Student对象

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

import java.sql.Date;

public class Student {
private int id;
private String name;
private String email;
private Date date;
public Student() {
super();
}
public Student(int id, String name, String email, Date date) {
super();
this.id = id;
this.name = name;
this.email = email;
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", email=" + email + ", date=" + date + "]";
}
}

C.插入一条Student记录

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

import java.sql.Date;
import java.util.Scanner;

import org.junit.Test;

public class TestJDBCOOP {
@Test
public void testAddStudent() {
Student stu = getStudentFromConsole();
addStudent(stu);
}
private Student getStudentFromConsole() {
Student stu = new Student();
Scanner scanner = new Scanner(System.in);
System.out.print("请输入学生ID:");
stu.setId(scanner.nextInt());
System.out.print("请输入学生Name:");
stu.setName(scanner.next());
System.out.print("请输入学生Email:");
stu.setEmail(scanner.next());
System.out.print("请输入学生Birth:");
stu.setDate(Date.valueOf(scanner.next()));
System.out.println(stu.getDate());
scanner.close();
return stu;
}
public void addStudent(Student stu) {
String sql = "INSERT INTO Student VALUES("
+ stu.getId() +",'"
+ stu.getName() + "','"
+ stu.getEmail() + "','"
+ stu.getDate() + "')";
System.out.println(sql);
JDBCTools.update(sql);
}
}

D.查询数据表

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

import java.io.FilterInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

import org.junit.Test;

public class TestJDBCOOP {
@Test
public void testSearchStudent() {
int type = getSearchType();
Student stu = searchStudent(type);
showMsg(stu);
}
private void showMsg(Student stu) {
if(stu == null) {
System.out.println("查无此人!");
}else {
System.out.println(stu);
}
}
private int getSearchType() {
System.out.print("请输入查询类型:1.id查询 2.姓名查询");
/*这里注意,若仍采用 Scanner scanner = new Scanner(System.in);
*当 scanner.close()时 System.in流也会被关闭,之后再用到该流时,
*会报 java.util.nosuchelementexception 异常
*/
Scanner scanner = new Scanner(new FilterInputStream(System.in){
@Override
public void close() throws IOException {
}
});
int type = scanner.nextInt();
scanner.close();
if(type != 1 && type != 2) {
System.out.println("输入的查询类型有误!");
throw new RuntimeException();
}
return type;
}
public Student searchStudent(int type) {
String sql = null;
Scanner scanner = new Scanner(System.in);
if(type == 1) {
System.out.print("请输入要查询的id:");
int id = scanner.nextInt();
sql = "SELECT * FROM Student WHERE id = " + id;
}else {
System.out.print("请输入要查询的Name:");
String name = scanner.next();
sql = "SELECT * FROM Student WHERE name = '" + name +"'";
}
scanner.close();
return getStudent(sql);
}
private Student getStudent(String sql) {
Connection conn = null;
Statement state = null;
ResultSet rs = null;
Student stu = null;
try {
conn = JDBCTools.getConnection();
state = conn.createStatement();
rs = state.executeQuery(sql);
if(rs.next()) {
stu = new Student(
rs.getInt(1),
rs.getString(2).trim(),
rs.getString(3).trim(),
rs.getDate(4));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.release(rs, state, conn);
}
return stu;
}
}

  注意: 一个方法A中使用了Scanner, 且在里面把它关闭了, 然后又在方法B里再用Scanner时Scanner in = new Scanner(System.in); 会报 java.util.nosuchelementexception 异常.

Java提供的IO包中, 一般都会处理资源级联关闭, 即关闭最外层包装的流, 内层被包被的流也会被关闭.

在Scanner类中使用了一个InputStreamReader()输入流, 对System.in进行再次包装. 当调用Scanner的close()方法时, 会执行InputStreamReader的关闭操作, 即调用用该包装类的close(). 该操作又会调用其内部包装的Sysetm.in的close操作.

若想解决关闭Scanner而不关闭System.in, 只需要对传入Scanner构造方法的System.in做下包装就可以了, 新包装的流要注意: 1.不产生新的流资源 2.是一个InputStream的实现类 3.close方法为空实现

你也可以利用上述方法, 解决其他类似的问题.

如下:

1
2
3
4
5
6
Scanner scanner = new Scanner(new FilterInputStream(System.in){
//当关闭到 FilterInputStream 对应的流时, 便不再向内层流关闭
@Override
public void close() throws IOException {
}
});

评论