美文网首页
JDBC学习1

JDBC学习1

作者: 张氏小毛驴 | 来源:发表于2022-03-26 13:53 被阅读0次

    一.JDBC基本概念

    JDBC,全拼为:Java DataBase Connectivity ,是一种Java程序访问数据库的标准接口。
    
    当使用Java程序访问数据库时,Java代码并不是直接就去操作数据库的,而是通过JDBC接口去访问,JDBC接口再通过JDBC驱动来实现真正的数据库访问。
    
    在Java中,JDBC接口是JDK自带的,可以直接调用,但是具体的JDBC驱动是根据不同的数据库厂商来提供的,其实也是java语言编写的,是一个jar包,在我们使用的时候导入相关的数据库驱动jar包就好了。(目的就在于同一套Java代码处理访问数据库的代码,但可以访问各种不同的数据库,根据数据库驱动去实现)
    
    Java与数据库驱动和数据库之间的关系,如下:
    
    JDBC.png

    好处:

    1. 使用同一套java代码,针对不同的数据库,不需要重新开发。
    2. 不受限于底层数据库,即使换一个其他数据库,java代码基本不变。

    总结:

    在开发时,只需完成对JDBC接口的调用,底层的数据库具体操作不需要我们去实现,由驱动完成。
    

    二.JDBC开发主要步骤

    先记录开发步骤,后面再详细学习各个对象。

    1. 导入驱动jar抱

      比如mysql,需要导入mysql-connector-java-5.1.37-bin.jar

      在idea中的导入的步骤:

      • 复制jar包到项目的lib文件夹下
      • 右键lib文件夹 --> Add As Library
    2. 注册驱动

    3. 获取数据库连接对象 Connection

    4. 定义sql语句

    5. 获取执行sql语句的对象 Statement/PreparedStatement

    6. 执行sql,接收返回结果

    7. 处理结果

    8. 释放资源

    有两种执行sql语句的对象:Statement和PreparedStatement版本(以后都是用PreparedStatement,区别下面再解释)

    Statement版本:

    public class JDBCDemo2 {
        public static void main(String[] args) {
            Connection conn = null;
            Statement state = null;
            try {
                // 1. 注册驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 2. 获取数据库连接对象Conn
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");
                // 3. 定义sql语句
                String sql = "insert into student3 values(15,'亚瑟',28,'男','深圳',80,85)";
                // 4. 获取执行sql对象
                state = conn.createStatement();
                // 5. 执行sql
                int count = state.executeUpdate(sql);
                if (count > 0) {
                    System.out.println("添加成功");
                } else {
                    System.out.println("执行失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 6. 释放资源
                if (state != null) {
                    try {
                        state.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    PreparedStatement版本

    public class JDBCDemo12 {
        public static void main(String[] args) {
            Connection conn = null;
            PreparedStatement pstate = null;
            ResultSet rs = null;
    
            try {
                // 1. 注册驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 2. 获取数据库连接对象Connection
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");
                // 3. 定义sql语句
                String sql = "select * from user where id = ?";
                // 4. 获取sql执行对象
                pstate = conn.prepareStatement(sql);
                pstate.setInt(1,2);
                // 5. 执行sql
                rs = pstate.executeQuery();
                // 6. 处理结果
                if (rs.next()) {
                    int id = rs.getInt("id");
                    String name = rs.getString("name");
                    String password = rs.getString("password");
    
                    System.out.println("id = " + id + ",name = " + name + ",password = " + password);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 7.释放资源
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (pstate != null) {
                    try {
                        pstate.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

    三.JDBC各个对象的详解

    • DriverManager:驱动管理对象

      作用:

      1. 用于管理和注册数据库驱动。

        使用方法:Class.forName("com.mysql.jdbc.Driver")

        查看Driver源码,发现在com.mysql.jdbc.Driver类中存在静态代码块

        public class Driver extends NonRegisteringDriver implements java.sql.Driver {
            public Driver() throws SQLException {
            }
        
            static {
                try {
                    DriverManager.registerDriver(new Driver());
                } catch (SQLException var1) {
                    throw new RuntimeException("Can't register driver!");
                }
            }
        }
        

        代码块里调用了DriverManager.registerDriver(new Driver())去注册给定的驱动程序

        注:mysql5之后可以省略注册驱动的步骤。也就是可以省略Class.forName("com.mysql.jdbc.Driver")

      2. 获取数据库连接对象。

        代码中使用方式:
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");

        使用方法:

        static Connection getConnection(String url, String user, String password):通过连接字符串,用户名和密码来获取数据库的连接对象。

        参数:

        • url:指定连接的路径,不同的数据库url是不同的。

          mysql的是:dbc:mysql://localhost:3306/数据库名字

        • user:数据库用户名

        • password:数据库密码

    • Connection:数据库连接对象

      Connection接口的具体实现是由数据库厂商实现的,代表了一个连接对象。

      作用:

      1. 获取执行sql的对象

        • Statement createStatement()
        • PreparedStatement prepareStatement(String sql)
      2. 管理事务

        事务管理就是指针对一系列的操作,这些操作要么同时成功,要么同时失败。

        • setAutoCommit(boolean autoCommit):开启事务,设置参数为false,即开启事务
        • commit():提交事务
        • rollback():回滚事务
    • Statement:执行sql语句的对象

      Statement是一个sql语句对象,用于发送sql给服务器,执行静态sql语句,并返回相关的结果对象。

      作用:

      1. 执行sql
        • int executeUpdate(String sql):用于执行增删改的操作(insert,update,delete),返回值是对数据库影响的行数。
        • ResultSet executeQuery(String sql):用于执行查询的操作(select),返回值为一个ResultSet结果集。
    • ResultSet:查询结果对象,封装了查询结果

      ResultSet是执行了查询操作executeQuery(String sql)后返回的一个对象,封装的是数据库返回的数据,把每一条记录封装成一个ResultSet对象。

      ResultSet提供了一些方法方便获取具体的数据:

      • getXxxx(参数):获取数据。

        提供了一系列的方法来获取不同类型的数据,比如:int getInt()String getString()

        数据类型依据于要获取的数据的那一列的数据类型。

        这个方法有两种传参方式:一种是传递int值,代表编号(编号从1开始),一种是传递String,代表列名称。

        比如:

        String getSrting(int columnIndex):传递参数为列的编号,从1开始的。

        String getString(String columnIndex):传递参数为列的名称。

      • boolean next():游标向下移动一行,判断当前行是否是最后一行(是否有数据),如果是最后一行,没有数据,则返回false,否则就返回true。

      基于ResultSet提供的方法,可以通过以下操作获取数据库返回的所有查询结果:

      // 循环判断是不是最后一行,如果是最后一行会返回false
      while (rs.next()) {
          // 获取这一条记录的每一列的数据
          int id = rs.getInt("id");
          String name = rs.getString(2);
          ...
      }
      
    • PreparedStatement:执行sql语句的对象

      1. 使用Statement存在问题:SQL注入问题

        在拼接SQL语句时,有一些SQL的特殊关键字参与字符串的拼接,会造成安全性问题

        举例:让用户输入用户名和密码,正确即可登录数据库。

        public class JDBCDemo7 {
            public static void main(String[] args) {
                String name;
                String pw;
                Connection conn = null;
                Statement state = null;
                ResultSet rs = null;
        
                // 1. 获取用户输入
                Scanner sc = new Scanner(System.in);
                System.out.print("请输入用户名:");
                name = sc.nextLine();
                System.out.print("请输入密码:");
                pw = sc.nextLine();
        
                // 2. 连接数据库
                try {
                    conn = JDBCUtil.getConnection();
                    // 定义sql
                    String sql = "select * from user where name='" + name + "'and password='" + pw + "'";
                    state = conn.createStatement();
                    rs = state.executeQuery(sql);
                    if (rs.next()) {
                        System.out.println("登录成功");
                    } else {
                        System.out.println("登录失败");
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    JDBCUtil.close(rs,state,conn);
                }
            }
        }
        

        当输入随意用户名,密码为:a' or 'a' = 'a时,会发现居然登录成功了!!!

        PreparedStatement.png

        这就是Statement带来的一个问题。

      2. 解决方法就是使用PreparedStatement(以后都是使用PreparedStatement来完成操作)

      3. PreparedStatement使用方法

        PreparedStatement使用?作为占位符,然后再调用方法填充数据,避免了字符串拼接的方式

        具体步骤是这样的(前面几个步骤和之前一样,这里从定义sql开始)

        • 定义sql,使用?作为占位符。

          比如:String sql = select * from user where username = ? and password = ?;

        • 获取执行sql的对象PreparedStatement

          pstate = conn.prepareStatement(sql);

        • 给sql语句的占位符?赋值

          使用PreparedStatement提供的方法:

          setXxxx(参数1,参数2):这个方法和ResultSet中的方法类似,也是根据数据类型调用对应的方法。

          • 参数1:占位符?的位置编号,从1开始。
          • 参数2:占位符?的值。

          比如:pstate.setInt(1,2);

        • 执行sql,获取返回结果,不需要再传递sql了(在获取PreparedStatement对象时候已经传递了)

          rs = pstate.executeQuery();

        • 处理结果

        • 释放资源

    四.实现自己的JDBC工具类:JDBCUtils

    在真正编写代码之后,我们发现每一次操作数据库,都要经历上述的至少7,8个步骤,步骤很繁琐,而且重复度很高,所以为了方便使用以及简化书写,可以把JDBC的相关操作抽取出来,作为一个工具类,提供相关方法供调用。
    
    步骤:
    
    1. 整合注册驱动部分,驱动的注册只需要注册一次即可,不需要每一次都注册。

      可以使用静态代码块,在第一次加载类时调用一次。

    2. 整合一个获取连接对象的方法

      数据库用户名,密码等信息可以通过配置文件获取,使用Properties集合类。

    3. 整合一个释放资源的方法

      针对不同操作,查询操作需要释放ResultSet,可以使用重载方法的方式提供同名的方法。

    public class JDBCUtil {
        private static String url;
        private static String root;
        private static String password;
        private static String driver;
    
        /*配置文件的读取,只需要读取一次即可,使用静态代码块*/
        static {
            // 读取资源文件,获取值
    
            // 1. 创建Properties集合类
            Properties pro = new Properties();
            // 获取src路径下的文件的方式 -- ClassLoader 类加载器
            ClassLoader classLoader = JDBCUtil.class.getClassLoader();
            URL res = classLoader.getResource("jdbc.properties");
            String path = res.getPath();
            // 2. 加载文件
            try {
                pro.load(new FileInputStream(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 3. 获取数据,赋值
            url = pro.getProperty("url");
            root = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            // 4. 注册驱动
            try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /* 获取连接对象 */
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, root, password);
        }
    
        public static void close(ResultSet rs, Statement state, Connection conn) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (state != null) {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void close(Statement state, Connection conn) {
            if (state != null) {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:JDBC学习1

          本文链接:https://www.haomeiwen.com/subject/umqsjrtx.html