栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDBC回顾

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDBC回顾

目录

什么是JDBC

JDBC编程六部曲:

一、java.sql.DriverManger【是sql包的类】

二、com.mysql .jdbc.Driver【mysql实现的接口(Driver)类 】

三、java.sql.Connection【接口】

四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】

五-四、java.sql.preparedStatement【Statement的子接口】

六、java.util.ResultSet【处理查询结果集(select)】

八、释放资源

代码演示

SQL注入问题

悲观锁和乐观锁的概念


什么是JDBC
  • JDBC其实就是SUN公司制定的一套接口(interface)【在 java.sql.*中】
  • 因为每一个数据的底层实现原理不一样。所以都是一堆接口。【降低耦合度】
  • java程序员都在面向JDBC接口写代码
  • 数据库厂家负责编写这些实现类,(一堆xxx.class 文件/mysql驱动jar包)【这些class文件需要去各大数据库的官网下载。注意: jdbc驱动的jar包一定要和mysql的版本兼容】
  • 为什么要面向接口编程:解耦合,降低程序的耦合度。提高程序的扩展力。【多态就是经典的面向抽象编程】
  • 注意:JDBC中所有下标从 1 开始

JDBC编程六部曲:
  1. 注册驱动【告诉java程序,即将要连接的是哪一个品牌的数据库】

  2. 获取连接【表示jvm的进程和数据库进程之间的通道 】

  3. 获取数据库对象【专门执行SQL语句的/数据库操作对象】

  4. 执行SQL语句【DML DQL】

  5. 处理查询结果集【只有执行select语句的时候,才有第五步处理查询结果】

  6. 释放资源【java和数据库之间属于进程间的通信】

一、java.sql.DriverManger【是sql包的类】     常用方法:
  1. 注册驱动方法
    1. static void registerDrver(Driver  driver);【需要一个Driver对象作为参数,抛出的异常:SQLException】
    2. 第二种方式【这种方式常用】
      1. 在Driver中有一个静态代码块。【静态代码块在类加载的时候会执行】
        1. Class. forName("com.mysql .jdbc.Driver");【不需要接收返回值。因为我们只要类加载这个行为动作】
        2. 这种方式常用的原因是参数是一个字符串,可以写在 一个属性配置文件中。【使用资源绑定器】
  2. 获取连接
    1. static Connection  getConnection(String url,String  user,String  password);【抛出的异常:SQLException。】
      1. URL/统一资源定位符:" jdbc:mysql://服务器ip地址 : 3306/资源名"【 协议 ip:端口号/资源名、资源名我们这里一般写数据库的名称】
      2. user:用户名
      3. password:用户密码

二、com.mysql .jdbc.Driver【mysql实现的接口(Driver)类 】
  • 这个实现类中有一个静态代码块。里面执行了注册驱动方法。

三、java.sql.Connection【接口】     常用方法
  1. 获得数据库操作对象
    1. Statement createStatement( );【抛出的异常:SQLException。因为返回值是Statement对象。所以不常用(后面有讲)】
    2. PreparedStatement prepareStatement(String SQL);【 常用】
      1. 需要一个SQL语句作为参数,返回一个预编译的数据库操作对象
      2. 并且sql语句中的动态拼接对象都变成" ?"【 一个 ?表示一个占位符,?不需要单引号括起来,一个?将来接收一个值】
      3. 这个语句会发送SQL语句框给DBMS,然后DBMS进行SQL语句的预先编译。
  2. void setAutoCommit(boolean autoCommit);【用来修改提交机制。默认自动提交】
    1. autoCommit:参数为true表示启用自动提交机制。false为禁用
  3. void commit( );【手动提交数据/事务】
  4. void rollback( );【数据/事务回滚。一般使用在catch中(如果不为空执行)】
    1. 就是数据库里做修改后( update ,insert , delete) 未 commit 之前 使用 rollback 可以 恢复数据到修改之前。
    2. 这句代码,假设在执行第一句执行完后,数据库服务器故障,抛出异常了,第二句就没有执行。这时候数据库的情况就是:id为1的name更新了,id为2的name没有更新。假设业务逻辑不能容忍这种只执行一半的情况,那么就应该rollback,把id为1的name恢复到一切执行之前的情况。
    3. 如果业务逻辑可以容忍这种只执行一半SQL的行为,那就不需要rollback。
    4. 数据库事务控制的精髓就一句话:对于一堆sql语句来说,要么都执行, 要么都不执行。其中“要么都不执行”的部分,就是用rollback实现的
注: JDBC中只要 执行任意一条DML语句,就提交一次 【有自动提交机制,一般需要修改为手动提交】

四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】
  • 编译一次就只能执行一次
  • 不做类型的安全检查
    常用方法【 执行SQL语句】:
  1. int  executeUpdate(String SQL );【可能执行insert、update、delete语句 增删改,或者不返回任何内容的语句(DML)】
    1. 注:返回值是执行改指定语句后 影响数据库中的记录条数
  2. ResultSet executeQuery( );【执行给定的SQL语句返回一个ResultSet对象】

五-四、java.sql.preparedStatement【Statement的子接口】
  • 预编译的sql对象
  • 编译一次可执行n次【效率高,因为mysql的底层原因】、
  • 编译时会做类型的安全检查【 编译时会多类型传参进行检查。方法要求只能是String类型实参】
  • 用来解决SQL 注入问题
常用方法:
  1. void setString(int x,String str);【因为已经预编译了,所以在这里面如果传了SQL语句也不会执行/编译,只编译一次】
    1. x表示给第几个占位符传值【下标从1开始】
    2. str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
    3. 注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
  2. void setInt (int n,int value );【根据占位符n传指定值给占位符。有多个类似方法。支持所有基本类型和引用数据类型。会查阅文档就行。这里就不赘述了】
  3. 执行SQL语句
    1. ResultSet   executeQuery ( );【执行SQL语句并返回查询结果集,不需要参数】
    2. int  executeUpdate( );【执行SQL语句并且返回影响数据的行数】

六、java.util.ResultSet【处理查询结果集(select)】     常用方法【这个接口中有很多方法,记得查阅文档】
  1. boolean next( );【从当前光标(指针)指向 下一行,初始时光标不指向任何元素】
  2. String getString(int columnIndex /String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
    1. int :根据参数的值拿当前行的指定列值【所有的列下标 从1开始 】
    2. String:str表示是列标签。通过列标签 去 拿当前行指定列的值,列标签不存在则报错【常用】
  3. int/short/ double…  getint/short/ double(int n /String str );【通过其他指定方法取指定类型的值】
  4. ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
  5. void last( );【光标/指针指向最后一行】
  6. int getRow( );【获取当前所在的行数,通过这两个方法可以 得到查询结果集一共有多少行】
七、 ResultSetMetaDate 【查询结果处理集封装的具体信息】     常用方法:
  1. int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
  2. String getColumnName(int n);【根据下标n拿去指定 列标签名】

八、释放资源
  1. 为了保证资源一定被释放,建议在finally预计块中关闭资源
  2. 并且遵循从小到大依次关闭【最先出来的最大】
  3. 关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。


代码演示
public class Text02 {
    public static void main(String[] args) {
        Connection ce= null;
        Statement st=null;
        ResultSet rs=null;
        ResultSetMetaData rsm=null;
        //这里是一个资源绑定器
        ResourceBundle rb=ResourceBundle.getBundle("day01/Text02p");
        String className=rb.getString("mysql");
        String url=rb.getString("url");
        String user=rb.getString("user");
        String password=rb.getString("password");
        //通过配置文件写入sql语句
        String sqlStatements =rb.getString("sqlStatements");
        try {
            //类加载的方式注册驱动
            Class.forName(className);
            //获取连接
            System.out.println(className);
            System.out.println(url);
            System.out.println(user);
            System.out.println(password);
           ce= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/diyige","root","123456");
//            cct=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/diige","root","123456");

            //获得处理结果集对象
            st=ce.createStatement();
           rs= st.executeQuery(sqlStatements);

           //通过rs处理查询结果集对象的方法得到所有的列名  格式化select查到的数据
          rsm= rs.getMetaData();
          int count=rsm.getColumnCount();
          String[] arr=new String[count];
            for(int i=1;i<=count;i++){
                //动态通过列标签拿值
                arr[i-1]=rsm.getColumnName(i);
                System.out.print(arr[i-1]+"tt");
            }

            System.out.println();
            System.out.println("*****************************************");
          while (rs.next()){
              for(int i=1;i<=count;i++){
                  //动态通过列标签拿值
                  System.out.print(rs.getString(arr[i-1])+"tt");
              }
              System.out.println();
          }


        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //关闭资源
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(st!=null){
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(ce!=null){
                try {
                    ce.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

SQL注入问题
  • 这个问题通常是基于在动态拼接SQL语句上的
  • SQL注入是一个安全问题,因为应用程序使用拼接SQL的技术而成为hacker攻击后台的方式。下面就介绍一下3种SQL注入,及解决SQL注入的方法。
  1. 下面以登录的机制为例,进行SQL注入的讲解。
    1. 基于 1=1 总为真
    2. SELECT * FROM Users WHERe UserId = 105 OR 1=1;
  2. 黑客只需在输入字段中插入105或1=1,就可以访问数据库中的所有用户名和密码。
    1. 基于 ""=""总为真
  3. SELECt * FROM Users WHERe Name ="" or ""="" AND Pass ="" or ""=""
    1. or “”=""总为真(等号左边等于等号右边)
  4. 基于批处理SQL
    1. SELECt * FROM Users WHERe UserId = 105; DROp TABLE Suppliers;
    2. 删除表Suppliers,很明显对数据库进行破坏,可能造成后台瘫痪。
  5. 防止SQL注入的解决方法---使用SQL参数
    1. txtUserId = getRequestString("UserId");
    2. sql = "SELECT * FROM Customers WHERe CustomerId = @0";
    3. command = new SqlCommand(sql);
    4. command.Parameters.AddWithValue("@0",txtUserID);
    5. command.ExecuteReader();
  6. 如何防止SQL注入

 1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。

 2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。

 3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

 4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。

 5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装

 6. sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。


悲观锁和乐观锁的概念

一、悲观锁/行级锁

  •  select * from Student where id=1 for update

    • 如果在select后面加了for update ,表示符合规则的每一行数据,在当前事务结束之前。所有人都不能更改这些指定行

    • 实际开发:当你在查询表的时候。不希望其他任何人修改就可以使用这个【当前线程会陷入阻塞。等待触发悲观锁的事务结束】

    • 事务必须得排队执行。数据锁住了,不允许并发

二、乐观锁

  • 多线程并发的时候,都可以对指定表的任何数据进行修改 

  • 支持并发,事务也不需要排队。只不过需要一个同一个版本号

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/873581.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号