JDBC的连接过程(二):操作数据库并断开连接

目录

回顾

上篇文章总结了使用JDBC与数据库建立连接的过程,方式一到方式五不断演进,推荐平时使用方式五。数据库连接建立后,我们就可以进一步对数据库的数据进行操作。

操作数据库的方式

上一篇文章我们创建了Connection对象,如果想操作数据库还要创建Statement对象,才能执行SQL语句。如果是执行查询操作,还需要用到ResultSet对象。
在java.sql包中有三个接口分别定义了对数据库的调用的不同方式:

  • Statement接口
  • PreparedStatement接口(Statement的子接口)
  • CallableStatement接口(PreparedStatement的子接口)

数据库准备

安装的MySQL一般都会包含test数据库,这个数据库里没有表,我们先创建一张学生表,设置name和password两个字段,为后面的操作做准备。

USE test;
CREATE TABLE stuinfo(name VARCHAR(20), password VARCHAR(20));
INSERT INTO stuinfo(name, password) VALUES('zhang', '123');
INSERT INTO stuinfo(name, password) VALUES('liu', '456');

Statement方式

获取连接后,创建Statement对象,定义sql语句,执行查询。
这段代码只是做个演示,没有关闭资源。

//StatementTest.java
import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class StatementTest { 
    @Test
    public void login() throws Exception { 
        //1.获取连接
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties prop = new Properties();
        prop.load(is);
        String driverClass = prop.getProperty("driverClass");
        String url = prop.getProperty("url");
        String user = prop.getProperty("user");
        String password = prop.getProperty("password");
        Class.forName(driverClass);
        Connection conn = DriverManager.getConnection(url, user, password);
        //2.创建Statement对象
        Statement st = conn.createStatement();
        //3.定义SQL语句
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入name:");
        String input_name = sc.nextLine();
        System.out.println(input_name);
        System.out.print("请输入password:");
        String input_password = sc.nextLine();
        System.out.println(input_password);
        String sql = "SELECT * FROM stuinfo WHERE name = '" + input_name + "' AND password = '" + input_password + "';";
        //4.返回查询结果,如果为空则登录失败,不为空则登陆成功
        ResultSet rs = st.executeQuery(sql);
        System.out.println(rs.next() ? "登录成功" : "登陆失败");
    }
}

测试结果

  • 测试一
请输入name:zhang
请输入password:123
登录成功
  • 测试二
请输入name:zhang
请输入password:456
登陆失败

使用Statement方式的弊端

  1. 存在拼接sql命令字符串的操作,很麻烦。
  2. 存在SQL注入问题。(其实SQL注入就是拼串造成的。)
    当name是1' OR,password是=1 OR '1'='1时,即使这条记录不存在数据库表中,也会查询成功,结果是所有的记录。因为拼接之后的SQL语句是这样的:
    SELECT * 
    FROM stuinfo
    WHERE name = '1' OR ' AND password = '=1 OR '1'='1';
    

    测试三

    请输入name:1' OR 
    请输入password:=1 OR '1'='1
    登录成功
    

PreparedStatement方式

如何避免上述Statement方式的弊端呢?我们可以用PreparedStatement方式。

插入

下面演示在数据库stuinfo表中插入记录。
代码:

//StatementTest.java

import org.junit.Test;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

public class StatementTest { 
    @Test
    public void login() { 
        Connection conn = null;
        PreparedStatement ps = null;
        try { 
            //1.获取连接
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
            Properties prop = new Properties();
            prop.load(is);
            String driverClass = prop.getProperty("driverClass");
            String url = prop.getProperty("url");
            String user = prop.getProperty("user");
            String password = prop.getProperty("password");
            Class.forName(driverClass);
            conn = DriverManager.getConnection(url, user, password);
            //2.预编译sql语句,返回PreparedStatement实例
            String sql = "insert into stuinfo(name, password) values(?, ?)";
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入name:");
            String input_name = scanner.nextLine();
            System.out.println(input_name);
            System.out.print("请输入password:");
            String input_password = scanner.nextLine();
            System.out.println(input_password);
            ps.setString(1, input_name);
            ps.setString(2, input_password);
            //4.执行操作
            ps.execute();
            System.out.println("插入成功");
        } catch (Exception e) { 
            e.printStackTrace();
        } finally { 
            //5.资源关闭
            try { 
                if (ps != null)
                    ps.close();
            } catch (SQLException e) { 
                e.printStackTrace();
            }
            try { 
                if (conn != null)
                    conn.close();
            } catch (SQLException e) { 
                e.printStackTrace();
            }
        }
    }
}

测试结果

请输入name:wang
请输入password:789
插入成功

数据库stuinfo表
《JDBC的连接过程(二):操作数据库并断开连接》

改进代码

上述代码每次操作数据库都要读取配置文件,建立连接,操作,关闭连接。可以把这些方法封装到一个JDBCUtils类里。

//JDBCUtils.java
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils { 
    public static Connection getConnection() throws Exception { 
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties prop = new Properties();
        prop.load(is);
        String driverClass = prop.getProperty("driverClass");
        String url = prop.getProperty("url");
        String user = prop.getProperty("user");
        String password = prop.getProperty("password");
        Class.forName(driverClass);
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }

    public static void closeResource(Connection conn, Statement st) { 
        try { 
            if (st!=null){ 
                st.close();
            }
        } catch (SQLException e) { 
            e.printStackTrace();
        }
        try { 
            if (conn != null) { 
                conn.close();
            }
        } catch (SQLException e) { 
            e.printStackTrace();
        }
    }
}

更新

更新数据库表中的某个字段的值。
代码:

//UpdateTest.java
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;

public class UpdateTest { 
    @Test
    public void update() { 
        Connection conn = null;
        PreparedStatement ps = null;
        try { 
            //1.获取数据库的连接
            conn = JDBCUtils.getConnection();
            //2.预编译sql语句,返回PreparedStatement实例
            String sql = "update stuinfo set password = ? where name = ?";
            ps = conn.prepareStatement(sql);
            //3.填充占位符
            ps.setString(1,"000");
            ps.setString(2,"zhang");
            //4.执行
            ps.execute();
            System.out.println("更新成功");
        } catch (Exception e) { 
            e.printStackTrace();
        } finally { 
            //5.资源的关闭
            JDBCUtils.closeResource(conn, ps);
        }
    }
}

测试结果

更新成功

数据库stuinfo表
《JDBC的连接过程(二):操作数据库并断开连接》

改进代码

除了查询以外,不管是增加,修改,删除,都是对数据表的更新,而且都没有返回值,操作都大致相同,即定义一个SQL语句,然后返回PreparedStatement实例,填充占位符,执行。那么,我们可以把这三种操作用一个update方法来定义。

删除

//UpdateTest.java
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;

public class UpdateTest { 

    public void update(String sql, Object... args) { 
        Connection conn = null;
        PreparedStatement ps = null;
        try { 
            conn = JDBCUtils.getConnection();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) { 
                ps.setObject(i + 1, args[i]);
            }
            ps.execute();
            System.out.println("执行完毕");
        } catch (Exception e) { 
            e.printStackTrace();
        } finally { 
            JDBCUtils.closeResource(conn, ps);
        }
    }

    @Test
    public void test() { 
        String sql = "delete from stuinfo where name=? and password=?";
        update(sql, "zhang", "000");
    }
}

测试结果

执行完毕

数据库stuinfo表
《JDBC的连接过程(二):操作数据库并断开连接》

查询

查询操作和增删改不一样,查询需要有返回,我们必须接收这个返回值。使用ResultSet接收。关闭资源时,ResultSet也需要关闭,所以我们再JDBCUtils类中再增加一个关闭资源的静态方法。

public static void closeResource(Connection conn, Statement st, ResultSet rs) { 
        closeResource(conn, st);
        try { 
            if (rs!=null)
                rs.close();
        } catch (SQLException e) { 
            e.printStackTrace();
        }
    }
//RetrieveTest.java
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class RetrieveTest { 
    @Test
    public void test() { 
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try { 
            conn = JDBCUtils.getConnection();
            String sql = "select name, password from stuinfo where name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "liu");
            rs = ps.executeQuery();
            while (rs.next()) { 
                String name = rs.getString(1);
                String password = rs.getString(2);
                System.out.println("name=" + name + ", password=" + password);
            }
        } catch (Exception e) { 
            e.printStackTrace();
        } finally { 
            JDBCUtils.closeResource(conn, ps, rs);
        }
    }
}

测试结果

name=liu, password=456

改进代码

在JDBC编程中有ORM编程思想,我们可以写出一个对于所有表更加通用的查询操作。这里篇幅已经很长了,在下一篇说。

    原文作者:渔舟舟
    原文地址: https://blog.csdn.net/realYuzhou/article/details/108450073
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞