前言
在上一篇章我们使用了 PreparedStatement 解决了 SQL 注入问题,那么再具体深入一下,我们来看看 PreparedStatement 如何实现 增删查改 的 操作。
使用PreparedStatement实现CRUD操作
1. PreparedStatement的使用
通过PreparedStatement完成增、删、改、查
1.1 PreparedStatement介绍
-
可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象
String sql = "select * from t_user where uname = ?"; // 设置SQL, 使用问号?设置查询的条件参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 获取preparedStatement PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
-
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数.
setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值
1.2 PreparedStatement vs Statement
代码的可读性和可维护性。
-
PreparedStatement 能最大可能提高性能:
- DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
- 在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。
- (语法检查,语义检查,翻译成二进制命令,缓存)
PreparedStatement 可以防止 SQL 注入
1.3 Java与SQL对应数据类型转换表
Java类型 | SQL类型 |
---|---|
boolean | BIT |
byte | TINYINT |
short | SMALLINT |
int | INTEGER |
long | BIGINT |
String | CHAR,VARCHAR,LONGVARCHAR |
byte array | BINARY , VAR BINARY |
java.sql.Date | DATE |
java.sql.Time | TIME |
java.sql.Timestamp | TIMESTAMP |
2.操作分析
- 注册驱动
- 获得连接
- 创建预编译sql语句对象
- 设置参数 执行
- 释放资源
3.实现
3.1 使用 PreparedStatement 完成数据插入
image-20210121090147924/**
* 使用 PreparedStatement 完成数据插入
*
* @throws Exception
*/
@Test
public void test08() throws Exception {
//1.获取连接
Connection connection = JdbcUtils.getConnection();
//2.使用 PreparedStatement 完成数据插入
//2.1 编写SQL语句: 插入一条数据
String sql = "insert into t_user values(null,?,?,?)";
//2.2 获取 PreparedStatement 并设置 参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 预编译sql语句
preparedStatement.setString(1, "特朗普"); // 设置第一个问号? 参数
preparedStatement.setString(2, "68");
preparedStatement.setString(3, "0");
//2.3 执行 SQL
int i = preparedStatement.executeUpdate();
System.out.println("插入的数据: " + i);
//3.释放资源
JdbcUtils.closeAll(preparedStatement, connection);
}
执行后,我们在 mysql 查询数据如下:
mysql> select * from t_user;
+----+-----------+------+------+
| id | uname | age | sex |
+----+-----------+------+------+
| 1 | zs | 18 | 1 |
| 2 | ls | 20 | 0 |
| 3 | ww | 23 | 1 |
| 4 | zl | 24 | 1 |
| 5 | lq | 15 | 0 |
| 6 | hh | 12 | 0 |
| 7 | wzx | 60 | NULL |
| 8 | lb | NULL | NULL |
| 10 | 特朗普 | 68 | 0 | -- 刚刚插入的数据
+----+-----------+------+------+
9 rows in set (0.00 sec)
mysql>
3.2 使用 PreparedStatement 完成数据更新
image-20210122083019799/**
* 使用 PreparedStatement 完成数据更新
*
* @throws Exception
*/
@Test
public void test09() throws Exception {
//1.获取连接
Connection connection = JdbcUtils.getConnection();
//2.使用 PreparedStatement 完成数据插入
//2.1 编写SQL语句: 更新 id = 10 的数据
String sql = "update t_user set uname = ? where id = 10";
//2.2 获取 PreparedStatement 并设置 参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 预编译sql语句
preparedStatement.setString(1, "拜登"); // 设置第一个问号? 参数
//2.3 执行 SQL
int i = preparedStatement.executeUpdate();
System.out.println("更新的数据: " + i);
//3.释放资源
JdbcUtils.closeAll(preparedStatement, connection);
}
查询更新后的数据如下:
mysql> select * from t_user;
+----+--------+------+------+
| id | uname | age | sex |
+----+--------+------+------+
| 1 | zs | 18 | 1 |
| 2 | ls | 20 | 0 |
| 3 | ww | 23 | 1 |
| 4 | zl | 24 | 1 |
| 5 | lq | 15 | 0 |
| 6 | hh | 12 | 0 |
| 7 | wzx | 60 | NULL |
| 8 | lb | NULL | NULL |
| 10 | 拜登 | 68 | 0 | -- 成功更新数据
+----+--------+------+------+
9 rows in set (0.00 sec)
mysql>
3.3 使用 PreparedStatement 完成数据删除
image-20210122084327356/**
* 使用 PreparedStatement 完成数据删除
*
* @throws Exception
*/
@Test
public void test10() throws Exception {
//1.获取连接
Connection connection = JdbcUtils.getConnection();
//2.使用 PreparedStatement 完成数据插入
//2.1 编写SQL语句: 更新 id = 10 的数据
String sql = "delete from t_user where id = ?";
//2.2 获取 PreparedStatement 并设置 参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 预编译sql语句
preparedStatement.setString(1, "10"); // 设置第一个问号? 参数
//2.3 执行 SQL
int i = preparedStatement.executeUpdate();
System.out.println("删除的数据: " + i);
//3.释放资源
JdbcUtils.closeAll(preparedStatement, connection);
}
3.4 使用 PreparedStatement 查询一条数据
image-20210122084703413/**
* 使用 PreparedStatement 查询一条数据
*
* @throws Exception
*/
@Test
public void test11() throws Exception {
//1.获取连接
Connection connection = JdbcUtils.getConnection();
//2.使用 PreparedStatement 完成数据插入
//2.1 编写SQL语句: 查询 id = 8 的数据
String sql = "select * from t_user where id = ?";
//2.2 获取 PreparedStatement 并设置 参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 预编译sql语句
preparedStatement.setString(1, "8"); // 设置第一个问号? 参数
//2.3 执行 SQL
ResultSet resultSet = preparedStatement.executeQuery();
User user = null;
while (resultSet.next()) {
user = new User(resultSet.getInt("id"),
resultSet.getString("uname"),
resultSet.getString("age"),
resultSet.getString("sex"));
}
System.out.println(user);
//3.释放资源
JdbcUtils.closeAll(preparedStatement, connection);
}
3.5 使用 PreparedStatement 查询多条数据
image-20210122085110940/**
* 使用 PreparedStatement 查询多条数据
*
* @throws Exception
*/
@Test
public void test12() throws Exception {
//1.获取连接
Connection connection = JdbcUtils.getConnection();
//2.使用 PreparedStatement 完成数据插入
//2.1 编写SQL语句: 查询 id = 8 的数据
String sql = "select * from t_user";
//2.2 获取 PreparedStatement 并设置 参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 预编译sql语句
//2.3 执行 SQL
ResultSet resultSet = preparedStatement.executeQuery();
ArrayList<User> users = new ArrayList<>(); // 使用集合存储所有查询的数据
while (resultSet.next()) {
User user = new User(resultSet.getInt("id"),
resultSet.getString("uname"),
resultSet.getString("age"),
resultSet.getString("sex"));
users.add(user);
}
// 打印查询的数据
for (User user : users) {
System.out.println(user);
}
//3.释放资源
JdbcUtils.closeAll(preparedStatement, connection);
}
4.小结
4.1步骤
- 注册驱动
- 获得连接
- 创建预编译sql语句对象
- 设置参数, 执行
- 释放资源
4.2API
- 创建预编译sql语句对象
connection.prepareStatement(String sql); //sql里面有参数, 先用?代替,进行占位
- 设置参数
prepareStatement.set类型(int 第几个问号,Object 值);
- 执行
Result result = prepareStatement.excuteQuery(); //执行查询 不传sql语句
int rows = prepareStatement.excuteUpdate(); //执行增删改 不传sql语句
4.3注意事项
?只能占参数,说白了就是列的值
?从1开始计数
执行的时候不要传入sql语句