编写工具类简化JDBC(CURD)的操作

JDBC

全称是JAVA DATE BASE Connectity(java数据库连接),可以为多种数据库提供统一的访问。即定义一个规范的接口,让各数据库厂商提供接口的具体实现类,这种实现类同时也被称作驱动。

JDBC规范

(4个核心对象)
- DriverManager:用于注册驱动。
- Connection:与数据库创建连接。
- Statement:操作数据库sql语句的对象。
- ResultSet:结果集(存放由select语句查询到的数据信息)

JDBC连接数据库的5个主要步骤

(即根据4个核心类对象推导出的步骤并封装)

1.加载驱动

方式一:
直接注册驱动

DriverManager.registerDriver(new Driver());

方式二:(推荐使用)
通过反射的方式,实现驱动的加载

Class.forName("com.mysql.cj.jdbc.Driver");

注意:

  • 在实际开发的过程中,不推荐使用方式一来进行驱动的注册,查看Driver源代码(如下)可以看到,它本身就加载了一次驱动,这样一来就会导致驱动程序注册两次,也就表示了在内存中会有两个Driver对象
  • 程序依赖mysql的jar包,一旦脱离,程序将无法编译,将来程序切换底层数据库将会非常麻烦。

Driver源代码

static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
  • 采用方式二不会导致驱动对象在内存中重复出现,程序仅需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。

2.建立连接

通过注册的JDBC驱动来建立数据库连接对象从而获取数据库的URL,用户名,密码来连接数据库

 String url = "jdbc:mysql://localhost:3306/day04?serverTimezone=UTC&characterEnconding=utf-8";
            Connection con = DriverManager.getConnection(url,"root","123456");

解析

String url = "jdbc:mysql://localhost:3306/day04?serverTimezone=UTC&characterEnconding=utf-8";

jdbc:是JDBC连接协议
mysq:// 是mysql数据库连接协议,即JDBC子协议
Localhost:3306 是主机和端口
day04 是指需要连接的数据库
serverTimezone=UTC:国际通用时区
characterEncoding=utf-8:数据库编码格式 (主要是解决数据库乱码的问题)

3.操作数据

方式一:(该方式有弊端,会导致sql注入问题)
通过数据库连接对象获取操作数据库sql语句的对象Statement

String sql = "select * from user where username = '"+name+"' and password = '"+passwd+"';";
            Statement stmt = con.createStatement();

模拟用户登录
需求:通过键盘录入来获取用户名和密码,同时在数据库中判断该用户是否存在
存在即登录成功,反之则失败。

代码一:

import java.sql.*;
import java.util.Scanner;

public class JDBCTest3 {

    public static void main(String[] args) {
        System.out.println("请输入用户名");
        String name = new Scanner(System.in).nextLine();
        System.out.println("请输入密码");
        String passwd = new Scanner(System.in).nextLine();
    //加载驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
        //建立连接
            String url = "jdbc:mysql://localhost:3306/day04?serverTimezone=UTC&characterEnconding=utf-8";
            con = DriverManager.getConnection(url,"root","123456");

        //操作数据
            String sql = "select * from user where username = '"+name+"' and password = '"+passwd+"';";
            stmt = con.createStatement();
            rs = stmt.executeQuery(sql);
            // 判断返回的结果
            if (rs.next()) {
                // 登录成功
                int id = rs.getInt("id");
                String u_name = rs.getString("username");
                String u_pwd = rs.getString("password");
                String email = rs.getString("email");
//                System.out.println(id + " : " + u_name + " : " + u_pwd + " : " + email);
                System.out.println("登录成功!");
            } else {
                // 登录失败
                System.out.println("登录失败! 用户名或密码错误!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                con = null;
            }

        }
    }
}

结果:

请输入用户名
lisi
请输入密码
123
登录成功!

由于对用户的输入没有进行充分的检查而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的。

案例一:
输入用户时: zhangsan’ or ‘1’=’1 password 随意
代码中sql语句进行拼接

select * from user where username ='zhangsan' or '1'='1' and password ='';

由于 and 优先级 执行 高于 or,导致不需要任何密码都能登录成功

请输入用户名
lisi' or '1'='1
请输入密码
00000000
登录成功!

案例二:
用户输入 username: zhangsan’ – password 随意
代码中sql语句进行拼接

select * from user where username ='zhangsan' -- ' and password ='' ;

在SQL添加 – 是mysql的注释

请输入用户名
lisi' -- 
请输入密码
111111
登录成功!

方式二:(推荐使用)
通过数据库连接对象获取操作数据库sql语句的对象PreparedStatement

String sql = "select * from user where username = ? and password = ?;";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1,name);
pstmt.setString(2,passwd);

解析:

  • ?表示占位符
  • 将带有?的SQL 发送给数据库完成预编译 ,在SQL编译后发现缺少两个参数。PreparedStatement 可以将? 代替参数发送给数据库服务器,因为SQL已经编译过,参数中特殊字符不会当做特殊字符编译,无法达到SQL注入的目的 。
  • setString(int parameterIndex, String x)
//表示给第一个?设置一个字符串类型的值
pstmt.setString(1,name);
  • PreparedStatement是Statement的子接口,它的实例对象可以通过调用Connection.preparedStatement(sql)方法获得,相对于Statement对象而言: PreperedStatement可以避免SQL注入的问题。 Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。

代码二:

import java.sql.*;
import java.util.Scanner;

public class JDBCTest3 {

    public static void main(String[] args) {
        System.out.println("请输入用户名");
        String name = new Scanner(System.in).nextLine();
        System.out.println("请输入密码");
        String passwd = new Scanner(System.in).nextLine();

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            String url = "jdbc:mysql://localhost:3306/day04?serverTimezone=UTC&characterEnconding=utf-8";
            con = DriverManager.getConnection(url,"root","123456");

            String sql = "select * from user where username = ? and password = ?;";
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1,name);
            pstmt.setString(2,passwd);


            rs = pstmt.executeQuery();
            // 判断返回的结果
            if (rs.next()) {
                // 登录成功
                int id = rs.getInt("id");
                String u_name = rs.getString("username");
                String u_pwd = rs.getString("password");
                String email = rs.getString("email");
//                System.out.println(id + " : " + u_name + " : " + u_pwd + " : " + email);
                System.out.println("登录成功!");
            } else {
                // 登录失败
                System.out.println("登录失败! 用户名或密码错误!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                pstmt = null;
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                con = null;
            }

        }
    }
}

结果

请输入用户名
lisi
请输入密码
123
登录成功!

4.获取操作数据

  • executeUpdate
    无结果集
    用于向数据库发送 insert/update/delete 语句,返回int 类型参数,代表影响记录行数.
int count = pstmt.executeUpdate();
  • executeQuery
    通过结果集获取操作数据库后的结果
    用于向数据库发送 select 语句,返回ResultSet 结果集对象.。
ResultSet rs = pstmt.executeQuery();
  • execute
    用于判断数据库发送任何SQL语句(包括 select/insert/update/delete) 返回boolean类型 ,SQL执行结果是select返回true,否则 false。
boolean flag = pstmt.execute();

5.释放资源

Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。

无结果集释放资源

public static void release(Connection con, Statement stmt) {
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            con = null;
        }

        if(stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }
    }

有结果集释放资源

public static void release(Connection con,Statement stmt,ResultSet rs) {
        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            con = null;
        }

        if(stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }

       release(rs);
    }

    public static void release(ResultSet rs) {
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
    }

对上述JDBC连接数据库并操作数据的步骤进行封装

  • 抽取数据库信息

    1. 抽取注册驱动依赖的mysql的jar包
    2. 抽取注册的JDBC驱动来建立数据库连接对象从而获取数据库的URL,用户名,密码
    3. 把以上抽取的对象放入配置文件中
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/day04?serverTimezone=UTC&characterEncoding=utf-8
username=root
passwd=123456

解析配置文件并对上述JDBC连接数据库的步骤进行封装

import java.sql.*;

public class JDBCUtils {

    private static final String DRIVERCLASS="com.mysql.cj.jdbc.Driver";
    private static final String URL="jdbc:mysql://localhost:3306/day04?serverTimezone=UTC" +
            "&characterEncoding=utf-8";
    private static final String USERNAME="root";
    private static final String PASSWD="123456";

    //加载驱动
    public static void loadDriver() {
        try {
            Class.forName(DRIVERCLASS);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("驱动加载失败");
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        String url = URL;
        Connection con = DriverManager.getConnection(url,USERNAME,PASSWD);

        return con;
    }

    //无结果集释放资源
    public static void realease(Connection con, Statement stmt) {
        if(stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }

        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            con = null;
        }
    }

    //有结果集释放资源
    public static void realease(Connection con, Statement stmt,ResultSet rs) {
        if(stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }

        if(con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            con = null;
        }

        realease(rs);
    }

    public static void realease(ResultSet rs) {
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
    }
}

测试:

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

public class JDBCTest5 {
    public static void main(String[] args) {
        Connection con = null;
        PreparedStatement pstmt = null;

        try {
            con = JDBCUTils2.getConnection();

            String sql = "update user set username = ?,password = ?,email = ? where id = ?;";
            pstmt = con.prepareStatement(sql);

            pstmt.setString(1,"jiuba");
            pstmt.setString(2,"888");
            pstmt.setString(3,"[email protected]");
            pstmt.setString(4,"2");

            int count = pstmt.executeUpdate();
            System.out.println(count);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUTils2.realease(con,pstmt);
        }
    }
}

结果

1

你可能感兴趣的:(DB)