JDBC一Java代码与MySQL的结合

一、JDBC

  1. JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这个类库可以以一种标准的方法、方便地访问数据库资源
  2. JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
  3. JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
    在这里插入图片描述在这里插入图片描述

二、获取数据库连接

Driver 接口

  1. java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现
  2. 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现
    Oracle的驱动:oracle.jdbc.driver.OracleDriver
    mySql的驱动: com.mysql.jdbc.Driver

加载与注册 JDBC 驱动

加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传
递要加载的 JDBC 驱动的类名
Class.forName(“com.mysql.jdbc.Driver”);

建立连接(Connection)

可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接
User,password可以用“属性名=属性值”方式告诉数据库;
JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
JDBC URL的标准由三部分组成,各部分间用冒号分隔。
jdbc:子协议:子名称
协议:JDBC URL中的协议总是jdbc
子协议:子协议用于标识一个数据库驱动程序
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
在这里插入图片描述

使用Statement操作数据表

数据库连接被用于向数据库服务器发送命令和 SQL 语句,在连接建立
后,需要对数据库进行访问,执行 sql 语句
在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
Statement

  • PreparedStatement
    • CallableStatement

弊端:SQL 注入攻击
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法

解决方案
于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从
Statement扩展而来) 取代 Statement 就可以了

使用PreparedStatement

可以通过调用 Connection 对象的 preparedStatement() 方法获取
PreparedStatement 对象
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开 始),第二个是设置的 SQL 语句中的参数的值

PreparedStatement vs Statement

  1. 代码的可读性和可维护性.
  2. PreparedStatement 能最大可能提高性能:
  3. DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
  4. 在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次.
  5. (语法检查,语义检查,翻译成二进制命令,缓存)
  6. PreparedStatement 可以防止 SQL 注入
    在这里插入图片描述

ResultSet

  1. 通过调用 PreparedStatement 对象的 excuteQuery() 方法创建该对象
  2. ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现
  3. ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过
    ResultSet 对象的 next() 方法移动到下一行

释放资源

  1. 释放ResultSet, Statement,Connection。
  2. 数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

三、案例


import java.sql.*;
import java.text.MessageFormat;

public class Jdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //以反射的方式装载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接对象
        final String URL = "jdbc:mysql://192.168.56.111:3306/school?useUnicode=true&characterEncoding=utf-8&useSSL=true"
               ,USERNAME = "root",PASSWORD = "kb08";
        Connection con = DriverManager.getConnection(URL,USERNAME,PASSWORD);

        //根据SQL命令创建执行对象
        //update操作
        /*
        final String SQL = "insert into empinfo(deptId,empName,empGender) value(?,?,?)";
        PreparedStatement pst = con.prepareStatement(SQL);
        //向SQL命令出入参数值
        pst.setObject(1,3);
        pst.setObject(2,"女汉子");
        pst.setObject(3,0);
        //执行操作
        int rst = pst.executeUpdate();
        */
        //查询操作
        final String SQL = "select * from empinfo where deptId=?";
        PreparedStatement pst = con.prepareStatement(SQL);
        pst.setObject(1,3);
        ResultSet rst = pst.executeQuery();
        ResultSetMetaData struct = rst.getMetaData();
//        for (int i = 1; i <=struct.getColumnCount(); i++) {
//            String columnLabel = struct.getColumnLabel(i);
//            String columnTypeName = struct.getColumnTypeName(i);
//            System.out.println(columnLabel);
//            System.out.println(columnTypeName);
//            System.out.println();
//        }
        String[] arr = new String[struct.getColumnCount()];
        while(rst.next()){
            for (int i = 1; i < arr.length; i++) {
                arr[i-1] = rst.getObject(i).toString();
            }
            System.out.println(MessageFormat.format("{0}\t{1}\t{2}\t{3}",arr));
        }
        rst.close();
        pst.close();
        con.close();
        //System.out.println(rst);
    }
}
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页