zoukankan      html  css  js  c++  java
  • JDBC(一)

    JDBC
    JDBC(Java Data Base Connectivity)JAVA连接数据库技术的简称,是JAVA连接各种数据库的能力
    连接的是关系对象型的数据库,Oracle SQLserver MYSQL

    API Application Interface 应用程序接口
    GUI Graphic User Interface 图形用户接口

    JDBC工作原理:
    SUN提供JDBC API集成在java.sql和javax.sql包中
    JDBC API主要包括:

    DriverManager类:启动管理器
    Connection接口:连接建立与数据库之间的桥梁
    Statement接口:处理器,执行负责将SQL语句发送到数据库
    ResultSet接口:结果集,通过查询得到的虚拟表

    JDBC作为Java应用程序与数据库连接的技术标准,本身并没有对JDBC API进行大量的实现,仅仅提供了数据库访问的抽象构建
    因此JDBC只是对数据库的连接与数据处理访问提供了一套规范标准,这些规范标准主要以接口、抽象类的形式呈现。这些API的具体实现是由数据库厂商来实现完成的
    JDBC驱动是不同数据库厂商

    数据库厂商对JDBC API完成实现后的工程进行打包(.jar)后的文件,又称为数据库连接驱动包

    JDBC的功能主要是实现如下处理:
    将应用程序和数据库进行连接
    执行SQL语句
    将执行语句得到的结果返回应用程序
    具体的分工:
    DriverManager负责管理加载的驱动
    Connection负责对数据库的连接
    Statement由Connection产生,负责执行SQL语句
    ResultSet保存Statement执行得到的结果(增删改返回的是受影响的行数)

    JDBC中包含的核心对象:
    Connection 连接接口对象,负责与数据库建立连接。由驱动管理器创建获得连接
    DriverManager 驱动管理对象,负责加载数据库驱动,并完成连接的处理

    用之前要先导入包:

      File——ProjectStructure——Libraries——点击加号——导入“mysql-connector-java-5.1.42-bin.jar”包

    DriverManager:

    public class DriverManager{
        //获取连接
        public Connection getConnection(){
        }
    }

    Connection:

    public interface Connection{
        //设置数据自动提交
        public void setAutoCommit(boolean flag){
        }
        //提交数据,完成数据的持久化
        public void commit(){
        }
        //关闭数据库的连接
        public void close(){
        }
        //获取处理器
        public Statement createStatement(){
        }
    }

    Statement:

    public interface Statement{
        //执行持久化操作,返回受影响的行数
        public int executeUpdate(String sql){
        }
        //执行查询,返回结果集
        public ResultSet executeQuery(String sql){
        }
        public void close(){
        }
    }

    JDBC进行数据库连接的方式主要有ODBC连接和纯JAVA驱动连接两种:
    1.ODBC连接时需要配置当前系统的数据源,也是开发中使用的方式
    2.JDBC不依赖当前系统环境,直接由驱动获取连接,仅用与操作系统提供的数据源进行访问连接

    JDBC进行数据库操作访问的步骤主要如下:
    1.加载驱动包
    2.通过驱动管理获取应用程序和数据库的连接
    3.通过连接获取处理器对象
    4.使用处理器执行SQL语句
    5.将执行得到的结果返回应用程序
    6.关闭使用到的各个对象

    URL 统一资源定位,用于在网络中查找定位到某一个精准位置的资源
    URL的书写格式: 协议名称://IP地址:端口/资源路径
    3306
    http:// ftp:// file://

    JAVA JDBC连接
    Class.forName(“com.mysql.jdbc.Driver”);
    Connection con=DirverManager.getConnection(“jdbc:mysql://ip地址:端口号:数据库名” , ”用户名” , ”密码”)

    Access denied for user ......说明用户名或者密码出现错误

    ClassNotFound......说明驱动路径或名称有错误

    No suitable driver found for jbdc1:......说明URL协议路径有错误

    Unknow Database......说明数据库名称写错了

    //通过反射实现驱动的加载
    Class.forName("com.mysql.jdbc.Driver");
    //通过驱动管理器获得连接对象
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/geekhome", "root", "root");
    System.out.println("数据库连接成功");

    使用处理器执行SQL语句:
    Statement stmt=con. createStatement();   //获得处理器
    int count=stmt.executeUpdate(SQL语句);    //使用处理器执行SQL语句,返回受影响行数
    ResultSet rs=stmt.executeQuery(SQL语句);    //使用处理器执行查询,返回结果集

    关闭对象:

      结果集.close();

      处理器.close();

      连接.close();

    数据修改:

    //通过连接对象获得处理器对象
    Statement stmt = connection.createStatement();
     //定义SQL语句
    String sql = "insert into users values(null,'rose','1999-10-5','rose@geekhome.com',null,20,'女')";
    String sql = "update users set age=21 where userid=104";
    //使用处理器执行SQL语句,返回受影响的行数
    int count = stmt.executeUpdate(sql);
    System.out.println("受影响的行数:"+count);
    //关闭对象
    stmt.close();
    connection.close();

    课件练习:

    将编号为102的员工的薪资降薪100

    删除编号为197的员工信息

    将工资最低的员工的薪资加薪10%

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.Statement;
    
    public class Demo1{
        public static void main(String[] args) throws Exception{
            //通过反射实现驱动的加载
            Class.forName("com.mysql.jdbc.Driver");
            //通过驱动管理器获得连接对象
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bbs_db", "root", "tjhilu");
            System.out.println("数据库连接成功");
            //通过连接对象获得处理器对象
            Statement stmt = connection.createStatement();
            //定义SQL语句
            String sql1 = "update emp set salary=salary-100 where employee_id=100";
            //使用处理器执行SQL语句,返回受影响的行数
            int count1 = ((Statement) stmt).executeUpdate(sql1);
            System.out.println("受影响的行数:"+count1);
    
            String sql2= "delete from emp where employee_id=107";
            int count2 = stmt.executeUpdate(sql2);
            System.out.println("受影响的行数:"+count2);
    
            String sql3="update emp set salary=salary*1.1 where employee_id in (select employee_id from (select employee_id from emp where salary=(select min(salary) from emp))n)";
            int count3 = stmt.executeUpdate(sql3);
            System.out.println("受影响的行数:"+count3);
            //关闭对象
            stmt.close();
            connection.close();
        }
    }

    查询数据:

    //创建处理器
    Statement stmt = connection.createStatement();
    //定义SQL语句
    String sql = "select * from dep";
    //执行查询 获得结果集对象
     ResultSet rs = stmt.executeQuery(sql);
    //此处打印只会打印结果集对象地址

    读取返回的结果:

    使用结果集获取查询结果
    while(rs.next()){
      //根据每列的类型调用不同的方法

      //如int型
      rs.getInt(列所在索引);
      //如Strig类型
      rs.getString(列所在索引);

    }

    //迭代结果集
    //next方法读取结果集中的下一行数据
    while(rs.next()){
        //每次循环表示读取到了一行
        //读到行之后,需要根据列的字段类型调用相应的get方法,获取行中的每个列的值
        //根据索引查找列值,索引从1开始
        int depId = rs.getInt(1);
        String depName = rs.getString(2);
        int locationId = rs.getInt(4);
        //获取列也可以根据列的名称访问
        int managerId = rs.getInt("manager_id");                                              
       System.out.println(depId+" "+depName+" "+locationId+" "+managerId); } //关闭对象 rs.close(); stmt.close();

    查询员工的姓名、薪水、入职时间、岗位(用日期函数接收数据库中的日期)

     public static void main(String[] args) {
            //查询员工的姓名、薪水、入职时间、岗位
            try {
                Class.forName("com.mysql.jdbc.Driver");
                //获得连接对象
                Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/geekhome", "root", "root");
                Statement stmt = connection.createStatement();
                String sql = "select concat(first_name,last_name) as empName,salary,hire_date,job_id from emp";
                //执行查询
                ResultSet rs = stmt.executeQuery(sql);
                while(rs.next()){
                    //列索引取决于查询后的结果集(sql),而不是原表的列索引
                    //String empName = rs.getString(1);
                    String empName = rs.getString("empName");
                    double salary = rs.getDouble(2);
                    //rs.getDate方法返回java.sql.Date 该类型仅包含年月日
                    //Date hireDate = rs.getDate(3);
                    //获取包含完整时间的类型需要使用getTimeStamp方法,TimeStamp继承自Date
                    Date hireDate = rs.getTimestamp(3);
                    String job = rs.getString(4);
        System.out.println(empName+"	"+salary+"	"+hireDate+"	"+job);
                }
                //关闭对象
                rs.close();
                stmt.close();
                connection.close();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }        

    SQL语句中如果出现了变量将导致语句的拼接容易出错,更容易产生数据库注入的安全问题

    使用PreparedStatement预处理解决上述问题

      预处理器有以下优点:

        1.提高数据处理的性能 (大幅度提高)

        2.允许使用占位符注入参数,防止SQL注入的问题

    处理器Statement和PreparedStatement的区别:

      常规处理器Statement在每次执行SQL语句时都会先对SQL语句进行编译()

      预处理器在创建时就要要求传入SQL语句,并在此时对SQL语句进行编译,将来每次调用时都不再执行编译的过程(因为将数据缓存在PreparedStatement中)

    使用预处理器时,SQL语句出现的变量使用?进行占位

    使用预处理器实现数据增删改:

      要求键盘输入用户的姓名、生日(输入字符串,将其转换成日期类型)、邮箱、年龄

      将输入的信息持久化至数据库中

     public static void main(String[] args)throws Exception {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入姓名:");
            String name = sc.nextLine();
            System.out.println("请输入生日:(yyyy-MM-dd)");
            String date = sc.nextLine();
            System.out.println("请输入邮箱:");
            String email = sc.nextLine();
            System.out.println("请输入年龄:");
            int age = sc.nextInt();
    
            //将字符类型的生日转换成Date类型
            Date birthday;
            birthday = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date);
    
            Class.forName("com.mysql.jdbc.Driver");
            //获得连接对象
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/geekhome", "root", "root");
          //用拼接方法传入变量
    // Statement stmt = connection.createStatement(); // //定义SQL语句 // String sql = "insert into users values(null,'"+name+"','"+date+"','"+email+"',null,"+age+",null)"; // System.out.println(sql); //使用预处理器时,SQL语句出现的变量使用?进行占位(只有在adbc中才能使用) String sql = "insert into users values(null,?,?,?,null,?,null)"; //通过预处理器解决SQL语句的注入问题 PreparedStatement pstmt = connection.prepareStatement(sql); //将变量注入至占位符中 //调用的set方法取决于占位符写入的值的类型 //第一个参数表示占位符的索引,从1开始,第二个参数是要写入的变量(会自动加上引号) pstmt.setString(1,name); //mysql的时间类型可以使用字符类型进行隐式转换 //pstmt.setString(2, date); pstmt.setTimestamp(2, new Timestamp(birthday.getTime())); pstmt.setString(3, email); pstmt.setInt(4, age); //执行SQL语句 pstmt.executeUpdate(); pstmt.close(); connection.close(); }

    使用预处理器实现模糊查询:

    例子:根据员工姓名进行模糊查询,打印显示所有员工的姓名、薪水、所在部门的名称

      public static void main(String[] args)throws Exception {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入要检索的姓名关键字");
            String nameKey = sc.nextLine();
    
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/geekhome","root","root");
            //创建SQL语句
            String sql = "select concat(first_name,last_name) as empName,salary,department_name " +
                    "from emp inner join dep on emp.department_id=dep.department_id" +
                    " where concat(first_name,last_name) like ?";
            //创建预处理器
            PreparedStatement pstmt = con.prepareStatement(sql);
            //注入参数
            pstmt.setString(1, "%"+nameKey+"%");
            //执行查询获得结果集
            ResultSet rs = pstmt.executeQuery();
            while(rs.next()){
                String empName = rs.getString(1);
                double salary = rs.getDouble(2);
                String depName = rs.getString(3);
                System.out.println(empName+"	"+salary+"	"+depName);
            }
            rs.close();
            pstmt.close();
            con.close();
        }

      获取结果集的元数据

      ResultSetMetaData

      该对象在执行后查询后,将会缓存结果集的数据结构

       public static void main(String[] args) throws Exception{
            String nameKey = "Steven";
    
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/geekhome","root","root");
            //创建SQL语句
            String sql = "select concat(first_name,last_name) as empName,salary,hire_date,department_name " +
                    "from emp inner join dep on emp.department_id=dep.department_id" +
                    " where concat(first_name,last_name) like ?";
            //创建预处理器
            PreparedStatement pstmt = con.prepareStatement(sql);
            //注入参数
            pstmt.setString(1, "%"+nameKey+"%");
            //执行查询获得结果集
            ResultSet rs = pstmt.executeQuery();
    //        while(rs.next()){
    //            String empName = rs.getString(1);
    //            double salary = rs.getDouble(2);
    //            String depName = rs.getString(3);
    //            System.out.println(empName+"	"+salary+"	"+depName);
    //        }
    
            //通过结果集获取元数据
            ResultSetMetaData metaData = rs.getMetaData();
            //获取数据列的数量
            int columnCount = metaData.getColumnCount();
            System.out.println("列的数量:"+columnCount);
            //根据列的数量循环遍历
            for(int i = 1; i <= columnCount; i++ ){
                //获取列的名称
                String colName = metaData.getColumnName(i);
                System.out.println(colName);
                //获取列的数据类型
                int type = metaData.getColumnType(i);
                System.out.println(type);
                //获取列的类型名称
                String typeName = metaData.getColumnTypeName(i);
                System.out.println(typeName);
            }
            rs.close();
            pstmt.close();
            con.close();
        }
  • 相关阅读:
    Educational Codeforces Round 86 (Rated for Div. 2)
    第十六届东南大学大学生程序设计竞赛(春、夏季)
    Codeforces Round #643 (Div. 2)
    [P3384] 【模板】轻重链剖分
    [BJOI2012] 连连看
    [CF1349C] Orac and Game of Life
    Codeforces Round #641 (Div. 2)
    [TJOI2018] 数学计算
    [CF1157D] N Problems During K Days
    [CF1163C1] Power Transmission (Easy Edition)
  • 原文地址:https://www.cnblogs.com/gfl-1112/p/12741503.html
Copyright © 2011-2022 走看看