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+"\t"+depName+"\t"+locationId+"\t"+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+"\t"+salary+"\t"+hireDate+"\t"+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+"\t"+salary+"\t"+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+"\t"+salary+"\t"+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();
    }

 

posted @ 2020-08-11 11:29  小小野生程序员sunny  阅读(167)  评论(0编辑  收藏  举报