学习JDBC时,使用到这三个类,这里简单的总结一下
1. PreparedStatement
- 是Statement的子接口,并且有一个同名的实现类
- 需要进行关闭资源的处理
- 相比于Statement接口,此接口更棒
- 避免了SQL注入的问题
- 书写 sql 语句时,需要进行字符串拼接的操作,麻烦
- 、、、、、、
- 常用方法
1. ResultSet executeQuery()
// 执行查询操作,并返回ResultSet对象
2. int executeUpdate()
// 执行更新操作
3. boolean execute()
// 执行对数据库的任意操作
4. setObject()、setString()、、、
// 以各种形式填充占位符,注意:占位符列表的索引从1开始
// 下面的方法涉及到批量处理数据
5. void addBatch()
// 把已经处理好的sql语句攒起来,暂时不执行,等调用executeBatch()方法的时候,再一起执行
6. int[] executeBatch()
// 执行攒起来的sql语句,并返回每条语句的执行结果形成的int数组【SUCCESS_NO_INFO=2 EXECUTE_FAILED=3】
7. void clearBatch()
// 执行完之后要将攒起来的sql语句清空
2. ResultSet
- ResultSet是结果集的意思
- 结果集就是select语句查询的结果,等同于一张表,而ResultSet就代表这张表
- 通过指针来表示表中的每一行,用指针来访问该结果集中的数据
- 结果集的指针默认是指向空的
- 需要进行关闭资源的处理
- 指针指向空时,如果有一条记录,也代表有下一条记录,返回true
- 常用方法
1. boolean next()
// 将光标从当前位置向后移一行
// 第一次调用next()方法时,结果集指针的指向第1条记录,之后再次调用,指针会自动向后移动一位
// next()方法的返回值是boolean类型,如果有下一条数据,返回true,没有下一条数据,返回false
// 指针指向空时,如果当前结果集中有一条记录,那么调用next()时也代表有下一条记录,返回true,此时再次调用就会返回false
2. String getObject(int columnIndex)
// 以Object的形式接收当前结果集中当前行指定列序号的值
3. String getObject(String columnLabel)
// 以Object的形式接收当前结果集中当前行指定列名的值
4. getInt(int columnIndex)、getLong(int columnIndex)、、、、、
// 有各种和第4个方法类似的方法,以不同的类型来接收数据,但是Object更通用
5. ResultSetMetaData getMetaData()
// 获取当前结果集的元数据
3. ResultSetMetaData
- 元数据(MetaData),就是描述其他数据的数据
- ResultSetMetaData 封装了描述 ResultSet 对象的数据,内部提供了方法来分析 ResultSet
- 需要进行关闭资源的处理,但是当ResultSet关闭时,对应的ResultSetMetaData会自动关闭
- 常用方法
1. int getColumnCount()
// 返回当前 ResultSet 对象中的列数
2. String getColumnLabel(int column)
// 获取字段名称,如果字段有别名,就获取该字段的别名,如果没有别名,就获取原名
3. String getColumnName(int column)
// 获取字段名称,如果字段有别名,会无法获取到值,此方法不可以用,如果没有别名,可以正常获取原名
// 下面两个方法是在网上查资料时学到的,暂时没有使用过
4. isNullable(int column)
// 指示指定列中的值是否可以为 null
5. int getColumnType(int column)
// 返回指定索引的列的类型
4. 应用
(1) 类结构
public class Stu {
private int age;
private String name;
// 下面是简写的方法
@Override
public String toString()
public int getAge()
public void setAge(int age)
public String getName()
public void setName(String name)
}
(2) 表结构
DROP TABLE IF EXISTS stu;
CREATE TABLE IF NOT EXISTS stu (
`name` VARCHAR(50),
`age` INT
);
(3) 更新数据
@Test
public void update() throws Exception {
// 1. 获取连接,stuDao里面有获取Connection对象的方法:getConnection(),下同
Connection conn = stuDao.getConnection();
// 2. 提供sql语句
String sql = "insert into stu(`name`, `age`) values(?, ?)";
// 3. 预编译sql语句
PreparedStatement ps = conn.prepareStatement(sql);
// 4. 填充已经被预编译过的sql语句的占位符
ps.setObject(1, "Tom");
ps.setObject(2, 26);
// 5. 执行操作
int update = ps.executeUpdate();
// 6. 查看执行结果
System.out.println(update);
// 7. 关闭资源
ps.close();
conn.close();
}
(4) 查询一条记录
@Test
public void query() throws Exception {
Stu stu = new Stu();
// 1. 获取连接
Connection conn = bookDao.getConnection();
// 2. 提供sql语句
String sql = "select `name`, `age` from stu where age = ?";
// 3. 预编译sql语句
PreparedStatement ps = conn.prepareStatement(sql);
// 4. 填充已经被预编译过的sql语句的占位符
ps.setObject(1, 19);
// 5. 执行操作,返回查询结果的结果集
ResultSet rs = ps.executeQuery();
// 6. 获取结果集的元数据
ResultSetMetaData md = rs.getMetaData();
// 7. 获取结果集的列数
int count = md.getColumnCount();
// 8. 移动结果集的指针,一次指向一行
while(rs.next()) {
// 9. 遍历数据的所有字段,每个字段的索引从1开始计算
for (int i = 1; i <= count; i ++ ) {
// 10. 获取第i个字段的名
String name = md.getColumnLabel(i);
// 11. 获取第i个字段的值
Object value = rs.getObject(i);
// 12. 通过反射将获取到的字段值赋值给Java对象对应的属性
Class<Stu> clazz = Stu.class; // 获取Stu类的Class对象
Field field = clazz.getDeclaredField(name); // 获取Java对象的指定属性
field.setAccessible(true); // 设置当前属性位可访问
field.set(stu, value); // 将字段值赋值给Java对象的属性
}
}
// 13. 查看结果
System.out.println(stu);
// 14. 关闭资源
rs.close();
ps.close();
conn.close();
}
(5) 查询多条记录
@Test
public void queryMore() throws Exception {
// 1. 获取连接
Connection conn = bookDao.getConnection();
// 2. 提供sql语句
String sql = "select `name`, `age` from stu";
// 3. 预编译sql语句
PreparedStatement ps = conn.prepareStatement(sql);
// 4. 填充已经被预编译过的sql语句的占位符
// 5. 执行操作,获得数据的结果集
ResultSet rs = ps.executeQuery();
// 6. 获取结果集的元数据
ResultSetMetaData md = rs.getMetaData();
// 7. 获取结果集的列数
int count = md.getColumnCount();
// 8. 声明List对象,用来存储每条记录
List<Stu> list = new ArrayList<>();
// 9. 移动结果集的指针,一次指向一行
while(rs.next()) {
Stu stu = new Stu();
// 10. 遍历当前行数据的所有字段,每个字段的索引从1开始计算
for (int i = 1; i <= count; i ++ ) {
// 11. 获取第i个字段的名
String name = md.getColumnLabel(i);
// 12. 获取第i个字段的值
Object value = rs.getObject(i);
// 13. 通过反射将获取到的字段值赋值给Java对象对应的属性
Class<Stu> clazz = Stu.class; // 获取Stu类的Class对象
Field field = clazz.getDeclaredField(name); // 获取Java对象的指定属性
field.setAccessible(true); // 设置当前属性位可访问
field.set(stu, value); // 将字段值赋值给Java对象的属性
}
list.add(stu);
}
// 14. 打印list里面的结果
list.forEach(System.out::println);
// 15. 关闭资源
rs.close();
ps.close();
conn.close();
}