0%

【JDBC】使用PreparedStatement实现CRUD操作

JDBC实现增删改查学习笔记

一、Statement简介

  • 在java.sql包中3个接口分别定义了对数据库的调用的不同方式:

    • (1)Statement:用于执行静态SQL语句并返回它所生成的结果的对象
    • (2)PrepareStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句
    • (3)CallableStatement:用于执行SQL存储过程
  • 注意: Satement是对SQL语句进行拼接,容易被钻漏洞(SQL注入)。所以一般会用PreparedStatement来代替Statement

    • PreparedStatement是Statement的子接口,是预编译的的Statement

二、实现增删改操作

  • 四种对数据库的操作,可以分为两类:增删改、查
    • 增删改:不需要返回值
    • 查:需要处理返回值

2.1实例

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
@Test
public void test() throws Exception{
FileInputStream fis = null;
Connection conn = null;
PreparedStatement ps = null;
try {
//1.创建输入流
fis = new FileInputStream("src\\jdbc.properties");
Properties pro = new Properties();
pro.load(fis);

//2.获取数据
String user = pro.getProperty("user");
String password = pro.getProperty("password");
String url = pro.getProperty("url");
String driverClass = pro.getProperty("DriverClass");

//3.反射加载驱动
Class.forName(driverClass);

//4.连接数据库
conn = DriverManager.getConnection(url, user, password);

//------------------------------------------------------------------------

//5.预编译sql语句,返回PreparedStatement对象
String sql = "insert into `customers`(name, email, birth) values(?, ?, ?)";//? 为 占位符
ps = conn.prepareStatement(sql);

//6.填充占位符
ps.setString(1,"C酱");//第一参数为占位符位置,从1开始算
ps.setString(2,"CC@gmail.com");

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2002-08-14");
ps.setDate(3, new java.sql.Date(date.getTime()));

//7.执行操作
ps.execute();
} catch (IOException e) {
e.printStackTrace();
} finally {
//8.资源关闭
if (ps != null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//9.try-catch-finally处理异常
}

2.2 封装方法修改实例

  • (1)新建一个JDBCUtils类,来封装数据库连接,资源关闭操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 连接数据,返回一个Connection对象
* @return Connection
* @throws Exception
*/
public static Connection getConncetion() throws Exception{
//1.创建输入流
FileInputStream fis = new FileInputStream("src\\jdbc.properties");
Properties pro = new Properties();
pro.load(fis);

//2.获取数据
String user = pro.getProperty("user");
String password = pro.getProperty("password");
String url = pro.getProperty("url");
String driverClass = pro.getProperty("DriverClass");

//3.反射加载驱动
Class.forName(driverClass);

//4.连接数据库
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 关闭资源
* @param conn
* @param ps
*/
public static void close(Connection conn, PreparedStatement ps){
if (ps != null){
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
  • (2)重新修改实例
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
@Test
public void test2(){
Connection conn = null;
PreparedStatement ps = null;
try {
//1.连接数据库
conn = JDBCUtils.getConncetion();

//2.预编译sql语句,返回PreparedStatement对象
String sql = "insert into `customers`(name, email, birth) values(?, ?, ?)";//? 为 占位符
ps = conn.prepareStatement(sql);

//3.填充占位符
ps.setString(1,"C酱");//第一参数为占位符位置,从1开始算
ps.setString(2,"CC@gmail.com");

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2002-08-14");
ps.setDate(3, new java.sql.Date(date.getTime()));

//4.执行操作
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.资源关闭
JDBCUtils.close(conn, ps);
}
//6.try-catch-finally处理异常
}

2.3 封装通用的增删改方法

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
/**
* 通用的sql增删改操作,传入的sql语句是带占位符的
* @param sql
* @param args
*/
public static void Update(String sql, Object ...args) throws Exception {
Connection conn = null;
PreparedStatement ps = null;
try {
//1.获取数据库连接
conn = JDBCUtils.getConncetion();

//2.sql语句预编译
ps = conn.prepareStatement(sql);

//3.填充占位符
for (int i = 0; i < args.length; i++){
ps.setObject(i+1, args[i]);
}

//4.执行sql语句
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.资源关闭
JDBCUtils.close(conn, ps);
}
//6.try-catch-finally处理异常
}
1
2
3
4
5
6
7
8
9
@Test
public void test3() {
try {
String sql = "delete from `customers` where name = ?";
JDBCUtils.Update(sql, "C酱");
} catch (Exception e) {
e.printStackTrace();
}
}

三、实现查找操作

3.1 概述

  • 查找操作对比其他操作,多了个对返回的数据进行接受、处理。
  • 对返回的数据,一般会创造一个类来进行接受,属于ORM编程思想,也是“万事万物皆对象”的体现

3.2 实现方法

  • (1)查询语句的执行方法是ResultSet executeQuery(),会返回一个结果集resultSet方法
  • (2)通过resultSet.next()方法来判断是否存在一行数据,有就返回true并指针下移,用于条件判断
  • (3)通过resultSet.getXxxx(index)来获取数据,因为要封装通用方法,一般使用getObject(index)
    • 注意:index是从1开始算,并不是0开始
  • (4)创建相应的对象,将获取的数据赋值到该对象中,一般使用反射方法
  • 注意: 步骤3需要知道一行数据到底有多少列数据;步骤4需要获取到列名,才能利用反射进行数据赋值(注意类的属性名,与查询的列名一致,不一致可以用sql语句别名的方式)
  • 解决方法:
    • (a)用resultSet.getMetaData()的方法来获取数据的原数据
    • (b)resultMetaData.getColumnCount()来获取列数,解决步骤3
    • (c)resultMetaData.getColumnLabel(index),获取列名,index从1开始,解决步骤4

3.3 实例

  • (1)查询特定表

    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
    public static UserTable queryForUserTable(String sql, Object ...args) {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
    //1.连接数据库
    conn = JDBCUtils.getConnection();

    //2.预编译sql
    ps = conn.prepareStatement(sql);

    //3.填充占位符
    for (int i = 0; i < args.length; i++) {
    ps.setObject(i+1, args[i]);
    }

    //4.执行并返回结果集
    rs = ps.executeQuery();

    //5.处理结果集
    ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的元数据
    int column = rsmd.getColumnCount();//获取列数

    //6.处理一行结果集
    if (rs.next()){
    UserTable u = new UserTable();//创建一个空参对象
    for (int i = 0; i < column; i++){
    //(1)获取列数据
    Object columnValue = rs.getObject(i + 1);

    //(2)获取列名
    String columnLabel = rsmd.getColumnLabel(i + 1);

    //(3)通过反射进行赋值赋值
    Class clazz = u.getClass();
    Field filed = clazz.getDeclaredField(columnLabel);
    filed.setAccessible(true);
    filed.set(u, columnValue);
    }
    return u;
    }
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    //7.资源关闭
    JDBCUtils.close(conn, ps, rs);
    }
    return null;
    }
  • (2)通过泛型,来实现查询任意表数据

    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
    public static <T> List<T> queryAll(Class<T> clazz, String sql, Object ...args){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
    //1.连接数据库
    conn = JDBCUtils.getConnection();

    //2.预编译sql
    ps = conn.prepareStatement(sql);

    //3.填充占位符
    for (int i = 0; i < args.length; i++) {
    ps.setObject(i+1, args[i]);
    }

    //4.执行并返回结果集
    rs = ps.executeQuery();

    //5.处理结果集
    ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的元数据
    int column = rsmd.getColumnCount();//获取列数

    //6.处理多行结果集
    ArrayList<T> list = new ArrayList<>();//创建一个List集合
    while (rs.next()){
    T t = clazz.getDeclaredConstructor().newInstance();//反射创建一个空参对象

    for (int i = 0; i < column; i++){
    //(1)获取列数据
    Object columnValue = rs.getObject(i + 1);

    //(2)获取列名
    String columnLabel = rsmd.getColumnLabel(i + 1);

    //(3)通过反射进行赋值
    Field filed = clazz.getDeclaredField(columnLabel);
    filed.setAccessible(true);
    filed.set(t, columnValue);
    }
    list.add(t);//添加对象
    }
    return list;
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    //7.资源关闭
    JDBCUtils.close(conn, ps, rs);
    }
    return null;
    }