• JDBC 常用类/接口详解(MySQL为例)


    DriverManager类

    java.sql.DriverManager 是用于管理一组JDBC驱动程序的基本服务。 

    注意: JDBC 2.0 API中新增的DataSource接口提供了另一种连接到数据源的方法。 使用DataSource对象是连接到数据源的首选方法。

    DriverManager类功能

    注册驱动

    告诉程序该使用什么数据库驱动jar

    可以直接使用DriverManager类的静态方法注册驱动:

    static void registerDriver(Driver driver)
    // 注册与给定的驱动程序 DriverManager 。 

    也可以间接使用该方法,如下介绍直接和间接调用DriverManager类的静态方法注册驱动。

     

    如我们要连接操作的是MySQL,那么我们就要注册驱动,告诉程序要使用MySQL驱动架包。如下就是注册MySQL数据库驱动:

    注册驱动第一种方法:

    Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
    // 将字节码文件Driver.java加载进内存,返回Driver.class对象。

    注册驱动第二种方法:

    com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
    DriverManager.registerDriver(driver);

    com.mysql.jdbc.Driver类中存在静态代码块,如下:

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    这里可以看出来,两种驱动方法其实都是一样的,都要用到静态方法registerDriver()

    备注:MySQL 5 之后的驱动jar包可以省略注册驱动的步骤。

    获取数据库连接

    方法

    static Connection getConnection(String url, String user, String password) 

    方法说明

    这是java.sql.DriverManager类的静态方法,用来获取数据库连接。该方法的返回值是Connection对象。
    
    参数说明:
    url:指定连接的路径
    user:用户名
    password:密码 
    
    
    连接的是MySQL数据库时,参数url格式举例说明
    语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
    例子:jdbc:mysql://localhost:3306/Study
    细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称

    Connection接口

    java.sql.Connection接口是一个数据库连接对象。它与特定数据库的连接(会话)。 执行SQL语句并在连接的上下文中返回结果。

    Connection接口功能

    获取执行SQL的对象

    方法:

    Statement createStatement()
    // 创建一个 Statement对象,用于将SQL语句发送到数据库。
    PreparedStatement prepareStatement(String sql)
    // 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。

    管理事务

    方法:

    开启事务

    void setAutoCommit(boolean autoCommit)
    // 将此连接的自动提交模式设置为给定状态。参数为false,即开启事务

    提交事务

    void commit()
    // 使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁。

    回滚事务

    void rollback()
    // 撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁。

    Statement接口

    java.sql.Statement接口,用于执行静态SQL语句并返回其生成的结果的对象。

    默认情况下,每个Statement对象只能有一个ResultSet对象同时打开。 因此,如果一个ResultSet对象的读取与另一个对象的读取交错,则ResultSet对象必须由不同的Statement对象生成。 在所有执行方法Statement接口隐式关闭当前ResultSet声明的对象,如果一个开放的存在。

    Statement接口功能

    执行静态SQL语句

    方法:

    boolean execute(String sql)
    // 执行给定的SQL语句,这可能会返回多个结果。该方法可以执行任意的SQL语句。
    int executeUpdate(String sql)
    // 执行给定的SQL语句。执行的是DML(insert、update、delete)语句、DDL(create,alter、drop)语句
    // 返回值是一个int类型的数 ———— 执行的SQL语句影响的行数
    ResultSet executeQuery(String sql)
    // 执行给定的SQL语句,该语句返回单个ResultSet对象。执行DQL(select)语句

    举例

    连接Study数据库,向account表中的id=1的balance字段值加上500。表数据如下:

    Java代码实现:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class JdbcDemo01 {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
    
            // 1、导入jar包:mysql-connector-java-5.1.48.jar
            // Add as Library ...
    
            // 2、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
    
            // 3、获取数据库连接对象
            Connection connection = DriverManager.getConnection(
                            "jdbc:mysql://localhost:3306/Study?useSSL=false",
                            "用户名", "密码");
    
            // 4、定义SQL语句
            // 将account表中的id=1的balance字段值加上500
            String sql = "UPDATE account Set balance = balance + 500 WHERE id = 1;";
    
            // 5、获取执行sql的对象 Statement
            Statement statement = connection.createStatement();
    
            // 6、执行SQL语句:执行成功,返回 1
            int returnResult = statement.executeUpdate(sql);
    
            // 7、查看是否执行成功
            System.out.println(returnResult);
    
            // 8、释放资源
            statement.close();
            connection.close();
        }
    }

    执行成功,控制台输出:1,说明影响的行数是一行。

    查看表中现在的数据:

    ResultSet接口

    表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。即该接口是结果集对象,用来封装查询结果。

    ResultSet对象保持一个光标指向其当前的数据行。 最初,光标位于第一行之前。 next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false ,因此可以在while循环中使用循环来遍历结果集。

    下面介绍几个具代表性的方法

    ResultSet接口功能

    游标向下移动一行

    boolean next()
    // 将光标从当前位置向前移动一行。

    获取数据

    getXxx(参数列表) 方法

    String getString(int columnIndex)
    // 这个检索的当前行中指定列的值 ResultSet对象为 String的Java编程语言。
    // int columnIndex:列的索引,索引从1开始,1对应第一列
    
    String getString(String columnLabel)
    // 这个检索的当前行中指定列的值 ResultSet对象为 String的Java编程语言。
    // String columnLabel:指定的列名称
    int getInt(int columnIndex)
    // 这个检索的当前行中指定列的值 ResultSet作为对象 int在Java编程语言。
    // int columnIndex:列的索引

    举例

    题目:查看account表中的记录,account表位于本地mysql的Study数据库下,端口号为3306

    account表

    account表如下:
    CREATE TABLE account (
        id INT PRIMARY KEY AUTO_INCREMENT,   -- id
        NAME VARCHAR(10),                    -- 名字
        balance DOUBLE                       -- 余额
    );
    INSERT INTO account (NAME, balance) VALUES ('LeeHua', 1500), ('Tom', 1000);

    Java程序实现:

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.sql.ResultSet;
    
    public class JdbcDemo03 {
        public static void main(String[] args) {
            Statement statement = null;
            Connection connection = null;
            ResultSet resultSet = null;
            try {
                // 1. 注册驱动
                Class.forName("com.mysql.jdbc.Driver");
    
                // 2. 定义SQL语句
                String sql = "SELECT * FROM account;";
    
                // 3.获取Connection对象
                connection = DriverManager.getConnection(
                        "jdbc:mysql:///Study?useSSL=false", "LeeHua", "qq562246926"
                );
    
                // 4.获取执行sql的对象 Statement
                statement = connection.createStatement();
    
                // 5.执行sql,返回查询结果(一个表),用ResultSet对象来封装。
                resultSet = statement.executeQuery(sql);
    
                // 6.处理结果
                // 6.1 循环判断游标是否是最后一行末尾。
                while(resultSet.next()){
                    // 获取数据
                    // 6.2 获取数据
                    // 获取 ID 字段的值
                    int id = resultSet.getInt(1);
                    // 获取name字段的值
                    String name = resultSet.getString("name");
                    // 获取balance字段的值
                    double balance = resultSet.getDouble(3);
                    // 输出
                    System.out.println(id + " --- " + name + " --- " + balance);
                }
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 7. 释放资源
                releaseResources(resultSet);
                releaseResources(statement);
                releaseResources(connection);
            }
        }
    
        public static <T> void releaseResources (T t){
            if(t != null){
                try {
                    // 利用反射,获取class对象
                    Class<?> aClass = t.getClass();
                    // 获取class对象中的方法对象
                    Method close = aClass.getMethod("close");
                    // 执行方法
                    close.invoke(t);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    }

    PreparedStatement接口

    PreparedStatement接口 extends Statement接口,表示预编译的SQL语句的对象。SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

    预编译的SQL:参数使用?作为占位符

    如:

    new Statement.executeQuery(sql1);
    
    new PreparedStatement.executeQuery(sql2);

    两个对象都执行SQL语句,Statement接口是执行静态SQL的,即已经拼接好的SQL,而PreparedStatement接口是执行预编译的SQL语句的。

    如:

    sql1 = "SELECT * FROM account WHERE id = ID AND balance = 账户余额;"
    
    sql2 = "SELECT * FROM account WHERE id = ? AND balance = ?;"

    sql1是静态的SQL语句,sql2是预编译SQL语句。

    PreparedStatement接口的用法和其父接口Statement的用法差不多,只是父接口是执行静态SQL语句的,而PreparedStatement接口是传入并执行预编译的SQL语句的。

    给?赋值

    方法: setXxx(参数1,参数2)

    参数说明:

    参数1:?的位置编号 从1 开始
    参数2:?的值

    如:

    void setInt(int parameterIndex, int x)
    // 将指定的参数设置为给定的Java int值。
    void setString(int parameterIndex, String x)
    // 将指定的参数设置为给定的Java String值。


    举例

    需求:获取数据库中字段的记录,对比用户输入,模拟登陆。

    实现

    自定义一个注解,用于获取部分值:

    package my.view.util;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE) // 注解能作用于类上
    @Retention(RetentionPolicy.RUNTIME) // 当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
    public @interface PropertiesAnnotation {
    
        /* URL */
        public abstract String url();
    
        /* 用户 */
        public abstract String user();
    
        /* 密码 */
        public abstract String password();
    
        /* 驱动包 */
        public abstract String driver();
    }

    创建一个MySQL表格:

    CREATE TABLE login (
        id INT PRIMARY KEY AUTO_INCREMENT,             -- id
        user VARCHAR(30),                              -- 用户名
        password VARCHAR(30)                           -- 密码
    );

    向表格中传入数据:

    INSERT INTO login (user, password) VALUES ('LeeHua', '123456'), ('Tom', 'abcdef');

    创建一个Jdbc工具类,用来注册驱动和获取连接对象:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    @PropertiesAnnotation(
            url = "jdbc:mysql:///Study", user = "mysql账号", password = "mysql密码", driver = "com.mysql.jdbc.Driver"
    )
    public class JdbcUtils02 {
    
        private static String url;
        private static String user;
        private static String password;
        private static String driver;
    
        /* 文件的读取,只需要读取一次即可拿到这些值。利用反射和注解、使用静态代码块 */
        static{
            // 读取资源文件,获取值。
    
            try {
                // 1. 解析注解
                // 1.1 获取JdbcUtils02类的字节码文件对象
                Class<JdbcUtils02> jdbcUtils02Class = JdbcUtils02.class;
    
                // 2. 获取上边的注解对象
                PropertiesAnnotation annotation = jdbcUtils02Class.getAnnotation(PropertiesAnnotation.class);
    
                // 3. 调用注解中定义的抽象方法,获取返回值,赋值给静态成员变量
                url = annotation.url();
                user = annotation.user();
                password = annotation.password();
                driver = annotation.driver();
    
                // 4. 注册驱动
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 获取连接
         * @return 连接对象
         */
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, user, password);
        }
    
    }
    View Code

    使用Statement接口,创建一个登录类:

    public boolean login(String user, String password) {
        if (user == null || password == null) {
            return false;
        }
        Connection connection =null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            // 获取数据库连接
            connection = JdbcUtils02.getConnection();
            // 定义SQL
            String sql = "SELECT * FROM login WHERE user = '" + user + "' AND password = '" + password + "';";
            // 获取执行SQL对象
            statement = connection.createStatement();
            // 执行查询
            resultSet = statement.executeQuery(sql);
            // 判断是否存在下一行数据
            return resultSet.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    使用PreparedStatement接口,创建一个登录类:

    public boolean login(String user, String password) {
        if (user == null || password == null) {
            return false;
        }
        Connection connection =null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 获取数据库连接
            connection = JdbcUtils02.getConnection();
            // 定义SQL
            String sql = "SELECT * FROM login WHERE user = ? AND password = ?;";
            // 获取执行SQL语句对象
            preparedStatement = connection.prepareStatement(sql);
            // 给?赋值
            preparedStatement.setString(1, user);
            preparedStatement.setString(2, password);
            // 执行SQL语句
            resultSet = preparedStatement.executeQuery();
            // 判断是否存在下一行数据
            return resultSet.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    模拟测试:登录方法在Demo类中。

    public class Demo {
    
        public static void main(String[] args) {
    
            // 键盘录入,接收用户名和密码
            Scanner scn = new Scanner(System.in);
            System.out.print("请输入用户名:");
            String userName = scn.nextLine();
            System.out.print("请输入密码:");
            String password = scn.nextLine();
    
            // 调用登录确认方法
            Demo demo08 = new Demo();
            if (demo.login(userName, password)) {
                System.out.println("登录成功!");
            } else {
                System.out.println("登录失败!用户名或密码额错误。");
            }
    
        }
    
    }
    • 调用使用Statement接口创建的登录方法测试:

    如果正常情况下输入,那么该方法判断用户账号密码是否正确是有效的。如果输入恒等式,那么该方法就失效了,无论输入什么恒等式,都可以登录,举例如:

    请输入用户名:LeeHua
    请输入密码:abc' OR 'abc' = 'abc

    那么这个时候,被拼接好的SQL语句就如下:

    SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';

    这是一条恒等式,不论 password是否正确,都可以登录成功,这是相当危险的,就像别人能够随随便便登录个人微信一样,安全隐患很大,所以我们使用预编译的SQL语句,不使用静态SQL语句。

    运行,控制台输出:登录成功!
    • 调用使用PreparedStatement接口创建的登录方法测试:

    这个时候无论输入什么,都会判断正确,因为这里传入的是一条预编译的SQL语句,并不是拼接的SQL语句。

    举例如:

    请输入用户名:LeeHua
    请输入密码:abc' OR 'abc' = 'abc

    那么这个时候实质传入的SQL语句是:

    SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';
    运行,控制台输出:登录失败!用户名或密码额错误。

    所以,判断用户名和密码是准确的。

              

  • 相关阅读:
    Server has no associated SOC machines or all SOC machines are at capacity
    没有启用集成windows身份验证
    Arcgis server常见问题
    把.NET程序部署到没有安装.NET Framwork的机器上
    将图片保存到数据库表中及从数据库表中读取图片并显示
    C#实现QQ靠边隐藏的功能
    手把手教你用C#打包应用程序(安装程序)【卸载模块已添加】
    DotNet下简单的程序部署
    部署.NET平台的程序实例浅析
    程序打包
  • 原文地址:https://www.cnblogs.com/liyihua/p/12324564.html
Copyright © 2020-2023  润新知