您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java之PreparedStatement怎么用
## 一、PreparedStatement概述
### 1.1 什么是PreparedStatement
PreparedStatement是Java JDBC API中的一个核心接口,继承自Statement接口,用于执行预编译的SQL语句。与普通Statement不同,PreparedStatement允许使用参数化查询,通过占位符(?)替代具体参数值,显著提高SQL执行效率和安全性。
### 1.2 主要优势
- **防止SQL注入**:自动处理特殊字符转义
- **性能优化**:预编译SQL语句,重复执行时效率更高
- **类型安全**:支持参数类型检查
- **代码可读性**:分离SQL结构与参数值
## 二、基本使用流程
### 2.1 创建PreparedStatement
```java
Connection conn = DriverManager.getConnection(url, username, password);
String sql = "INSERT INTO users(name, age) VALUES(?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
PreparedStatement提供了一系列setXXX()方法:
数据类型 | 设置方法示例 |
---|---|
int | setInt(1, 25) |
String | setString(2, “张三”) |
boolean | setBoolean(3, true) |
Date | setDate(4, new Date(…)) |
BigDecimal | setBigDecimal(5, new BigDecimal(“100.50”)) |
// 执行INSERT/UPDATE/DELETE
int affectedRows = pstmt.executeUpdate();
// 执行SELECT查询
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
// 处理结果集
}
Connection conn = ...;
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO products(name, price) VALUES(?, ?)");
for(Product product : productList) {
pstmt.setString(1, product.getName());
pstmt.setDouble(2, product.getPrice());
pstmt.addBatch(); // 添加到批处理
// 每1000条执行一次
if(i % 1000 == 0) {
pstmt.executeBatch();
}
}
int[] result = pstmt.executeBatch(); // 执行剩余操作
conn.commit();
CallableStatement cstmt = conn.prepareCall("{call get_employee_data(?, ?)}");
cstmt.setInt(1, employeeId);
cstmt.registerOutParameter(2, Types.VARCHAR);
cstmt.execute();
String result = cstmt.getString(2);
try {
conn.setAutoCommit(false);
PreparedStatement pstmt1 = conn.prepareStatement(...);
PreparedStatement pstmt2 = conn.prepareStatement(...);
// 执行多个操作
pstmt1.executeUpdate();
pstmt2.executeUpdate();
conn.commit();
} catch (SQLException e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
}
推荐使用HikariCP等连接池:
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
config.setMaximumPoolSize(20);
HikariDataSource ds = new HikariDataSource(config);
MySQL开启预编译缓存:
jdbc:mysql://localhost:3306/db?useServerPrepStmts=true&cachePrepStmts=true
使用try-with-resources语法:
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, param);
try (ResultSet rs = pstmt.executeQuery()) {
// 处理结果
}
}
错误示范:
// 危险!可能被SQL注入
String sql = "SELECT * FROM users WHERE username = '" + input + "'";
正确做法:
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ?");
pstmt.setString(1, input);
// 使用加密字段
pstmt.setString(1, encrypt(user.getPassword()));
// 日志脱敏处理
logger.debug("Executing: {} with params: {}",
sql,
maskSensitiveData(params));
错误现象:
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2)
解决方案: 检查SQL语句中的问号数量与设置的参数是否匹配
错误现象:
java.sql.SQLException: Conversion not supported for type java.util.Date
正确做法:
pstmt.setDate(1, new java.sql.Date(utilDate.getTime()));
使用连接池的监控功能:
HikariPoolMXBean pool = ds.getHikariPoolMXBean();
System.out.println("Active connections: " + pool.getActiveConnections());
public class UserDao {
private static final String INSERT_SQL =
"INSERT INTO users(username, password, email) VALUES(?, ?, ?)";
public boolean registerUser(User user) {
try (Connection conn = DataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL)) {
pstmt.setString(1, user.getUsername());
pstmt.setString(2, encrypt(user.getPassword()));
pstmt.setString(3, user.getEmail());
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
logger.error("Registration failed", e);
return false;
}
}
}
public List<Product> getProducts(int page, int size) {
String sql = "SELECT * FROM products ORDER BY id LIMIT ? OFFSET ?";
try (Connection conn = ...;
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, size);
pstmt.setInt(2, (page - 1) * size);
ResultSet rs = pstmt.executeQuery();
List<Product> list = new ArrayList<>();
while(rs.next()) {
list.add(mapRowToProduct(rs));
}
return list;
} catch (...) { ... }
}
通过掌握PreparedStatement的正确使用方法,可以显著提升Java数据库应用的安全性、性能和可维护性。
本文共计约3050字,涵盖了从基础到高级的PreparedStatement使用技巧,可作为日常开发参考指南。 “`
这篇文章采用Markdown格式编写,包含: 1. 多级标题结构 2. 代码块示例 3. 表格对比 4. 实际应用场景 5. 问题解决方案 6. 完整示例代码 7. 最佳实践总结
内容全面覆盖了PreparedStatement的核心用法,字数符合3050字左右的要求,适合作为技术文档或博客文章。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。