java-web/docs/tasks/chapter06-tasks.md
2024-08-08 15:18:09 +08:00

221 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 6. 数据库访问
### 6.1 JDBC
#### 6.1.3 实现第一个JDBC程序
**练习任务**:
1. **创建数据库表**:
- 根据PetClinic中的`Owner`实体模型创建一个表,包含`id`(整数,主键,自增)、`firstName`字符串长度255不可为空、`lastName`字符串长度255不可为空、`address`字符串长度255、`city`字符串长度255、`telephone`字符串长度255字段。
- 示例代码:
```java
private static void createOwnerTable(Connection conn) throws SQLException {
String sql = "CREATE TABLE IF NOT EXISTS owners (" +
"id INT AUTO_INCREMENT PRIMARY KEY," +
"firstName VARCHAR(255) NOT NULL," +
"lastName VARCHAR(255) NOT NULL," +
"address VARCHAR(255)," +
"city VARCHAR(255)," +
"telephone VARCHAR(255))";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.executeUpdate();
}
}
```
2. **插入业主记录**:
- 向`owners`表中插入两条记录。
- 示例代码:
```java
private static void insertOwners(Connection conn) throws SQLException {
String sql = "INSERT INTO owners (firstName, lastName, address, city, telephone) VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "Alice");
pstmt.setString(2, "Johnson");
pstmt.setString(3, "123 Main St");
pstmt.setString(4, "Springfield");
pstmt.setString(5, "555-1234");
pstmt.executeUpdate();
pstmt.setString(1, "Bob");
pstmt.setString(2, "Smith");
pstmt.setString(3, "456 Elm St");
pstmt.setString(4, "Springfield");
pstmt.setString(5, "555-5678");
pstmt.executeUpdate();
}
}
```
3. **查询业主记录**:
- 查询`owners`表中的所有记录,并打印出每条记录的信息。
- 示例代码:
```java
private static void queryOwners(Connection conn) throws SQLException {
String sql = "SELECT * FROM owners";
try (PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
String firstName = rs.getString("firstName");
String lastName = rs.getString("lastName");
String address = rs.getString("address");
String city = rs.getString("city");
String telephone = rs.getString("telephone");
System.out.println("ID: " + id + ", First Name: " + firstName + ", Last Name: " + lastName + ", Address: " + address + ", City: " + city + ", Telephone: " + telephone);
}
}
}
```
4. **更新业主记录**:
- 更新`owners`表中名字为"Alice Johnson"的业主的电话号码为"555-1111"。
- 示例代码:
```java
private static void updateOwner(Connection conn) throws SQLException {
String sql = "UPDATE owners SET telephone = ? WHERE firstName = ? AND lastName = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "555-1111");
pstmt.setString(2, "Alice");
pstmt.setString(3, "Johnson");
int rowsUpdated = pstmt.executeUpdate();
System.out.println(rowsUpdated + " row(s) updated.");
}
}
```
5. **删除业主记录**:
- 删除`owners`表中名字为"Bob Smith"的业主记录。
- 示例代码:
```java
private static void deleteOwner(Connection conn) throws SQLException {
String sql = "DELETE FROM owners WHERE firstName = ? AND lastName = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "Bob");
pstmt.setString(2, "Smith");
int rowsDeleted = pstmt.executeUpdate();
System.out.println(rowsDeleted + " row(s) deleted.");
}
}
```
6. **完整程序**:
- 将以上步骤整合到一个完整的程序中确保正确加载MySQL驱动、建立数据库连接并处理异常。
- 示例代码:
```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcCrudExample {
private static final String DB_URL = "jdbc:mysql://localhost:3306/petclinic";
private static final String USER = "root";
private static final String PASS = "password";
public static void main(String[] args) {
Connection conn = null;
try {
// 加载MySQL驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取数据库连接
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// 创建表
createOwnerTable(conn);
// 插入记录
insertOwners(conn);
// 查询记录
queryOwners(conn);
// 更新记录
updateOwner(conn);
// 删除记录
deleteOwner(conn);
// 再次查询记录
queryOwners(conn);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
// 其他方法...
}
```
### 6.3 SQL注入的预防措施
**练习任务**:
1. **使用PreparedStatement防止SQL注入**:
- 修改上述的`queryOwners`方法,使用`PreparedStatement`来执行查询。
- 示例代码:
```java
private static void queryOwners(Connection conn) throws SQLException {
String sql = "SELECT * FROM owners WHERE firstName = ? AND lastName = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "Alice");
pstmt.setString(2, "Johnson");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String firstName = rs.getString("firstName");
String lastName = rs.getString("lastName");
String address = rs.getString("address");
String city = rs.getString("city");
String telephone = rs.getString("telephone");
System.out.println("ID: " + id + ", First Name: " + firstName + ", Last Name: " + lastName + ", Address: " + address + ", City: " + city + ", Telephone: " + telephone);
}
}
}
```
### 6.2 数据库连接池
#### 6.2.4 使用HikariCP实现数据库连接池
**练习任务**:
1. **配置HikariCP连接池**:
- 使用HikariCP配置一个连接池并使用它来获取数据库连接。
- 示例代码:
```java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class HikariCpExample {
public static void main(String[] args) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/petclinic");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);
config.setConnectionTimeout(30000);
HikariDataSource ds = new HikariDataSource(config);
try (Connection conn = ds.getConnection()) {
// 使用连接执行数据库操作
System.out.println("Database connection established.");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
```