JDBC原理介绍以及增删改查示范

一 原理

Java程序/J2EE程序操作数据库通常就是对数据库中某一个或者某些表进行增删改查。那么就需要通过某些方式连接到数据库,比如MySQL,执行各种SQL语句(insert、select、udpate)。

JDBC(Java Database Connectivity Java数据库连接技术)只是java程序操作数据库中最原始和最基础的一种方式,实际在项目中,我们一般不会直接使用JDBC,而是会使用J2EE的一些开源框架,比如MyBatis、Hibernate。其实我们可以理解为其代表了JDK提供的一项面向数据库的一套开发接口。换句话说JDBC真正的意义在于通过接口统一了Java程序对各种数据库的访问规范。

数据库厂商(比如MySQL或者Oracle)提供的JDBC驱动,针对JDBC的一套接口,提供完成的接口实现。在实现类中,不同的数据库厂商就实现了针对自己数据库的一套连接、执行SQL语句等等实际功能。

二 增删改查示例

下面我们写一个简单的增删改查示例类。

/**
 * JDBC增删改查示范类
 * 
 * @author Administrator
 *
 */
public class JdbcCRUDTest {

  public static void main(String[] args) {
    // insert();
    // update();
    // delete();
    // select();
    preparedStatement();
  }

  /**
   * 测试插入数据
   */
  private static void insert() {
    // 总结一下JDBC的最基本的使用过程
    // 1、加载驱动类:Class.forName()
    // 2、获取数据库连接:DriverManager.getConnection()
    // 3、创建SQL语句执行句柄:Connection.createStatement()
    // 4、执行SQL语句:Statement.executeUpdate()
    // 5、释放数据库连接资源:finally,Connection.close()

    // 定义数据库连接对象
    // 引用JDBC相关的所有接口或者是抽象类的时候,必须是引用java.sql包下的
    // java.sql包下的,才代表了java提供的JDBC接口,只是一套规范
    // 至于具体的实现,则由数据库驱动来提供,切记不要引用诸如com.mysql.jdbc包的类
    Connection conn = null;

    // 定义SQL语句执行句柄:Statement对象
    // Statement对象,其实就是底层会基于Connection数据库连接
    // 可以让我们方便的针对数据库中的表,执行增删改查的SQL语句
    // 比如insert、udpate、delete和select语句
    Statement stmt = null;

    try {
      // 第一步,加载数据库的驱动,我们都是面向java.sql包下的接口在编程,所以
      // 要想让JDBC代码能够真正操作数据库,那么就必须第一步先加载进来你要操作的数据库的驱动类
      // 使用Class.forName()方式来加载数据库的驱动类
      // Class.forName()是Java提供的一种基于反射的方式,直接根据类的全限定名(包+类)
      // 从类所在的磁盘文件(.class文件)中加载类对应的内容,并创建对应的Class对象
      Class.forName("com.mysql.jdbc.Driver");

      // 获取数据库的连接
      // 使用DriverManager.getConnection()方法获取针对数据库的连接
      // 需要给方法传入三个参数,包括url、user、password
      // 其中url就是有特定格式的数据库连接串,包括“主协议:子协议://主机名:端口号//数据库”
      conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp_database", "root",
          "root");

      // 基于数据库连接Connection对象,创建SQL语句执行句柄,Statement对象
      // Statement对象,就是用来基于底层的Connection代表的数据库连接
      // 允许我们通过java程序,通过Statement对象,向MySQL数据库发送SQL语句
      // 从而实现通过发送的SQL语句来执行增删改查等逻辑
      stmt = conn.createStatement();

      // 然后就可以基于Statement对象,来执行insert SQL语句了
      // 插入一条数据
      // Statement.executeUpdate()方法,就可以用来执行insert、update、delete语句
      // 返回类型是个int值,也就是SQL语句影响的行数
      String sql = "insert into test_user(name,age) values('李四',26)";
      int rtn = stmt.executeUpdate(sql);

      System.out.println("SQL语句影响了【" + rtn + "】行。");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      // 最后一定要记得在finally代码块中,尽快在执行完SQL语句之后,就释放数据库连接
      try {
        if (stmt != null) {
          stmt.close();
          stmt = null;
        }
        if (conn != null) {
          conn.close();
          conn = null;
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }

  /**
   * 测试更新数据
   */
  private static void update() {
    Connection conn = null;
    Statement stmt = null;

    try {
      Class.forName("com.mysql.jdbc.Driver");

      conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp_database", "root",
          "root");
      stmt = conn.createStatement();

      String sql = "update test_user set age=27 where name='李四'";
      int rtn = stmt.executeUpdate(sql);

      System.out.println("SQL语句影响了【" + rtn + "】行。");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
          stmt = null;
        }
        if (conn != null) {
          conn.close();
          conn = null;
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }

  /**
   * 测试删除数据
   */
  private static void delete() {
    Connection conn = null;
    Statement stmt = null;

    try {
      Class.forName("com.mysql.jdbc.Driver");

      conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp_database", "root",
          "root");
      stmt = conn.createStatement();

      String sql = "delete from test_user where name='李四'";
      int rtn = stmt.executeUpdate(sql);

      System.out.println("SQL语句影响了【" + rtn + "】行。");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
          stmt = null;
        }
        if (conn != null) {
          conn.close();
          conn = null;
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }

  /**
   * 测试查询数据
   */
  private static void select() {
    Connection conn = null;
    Statement stmt = null;
    // 对于select查询语句,需要定义ResultSet
    // ResultSet就代表了,你的select语句查询出来的数据
    // 需要通过ResutSet对象,来遍历你查询出来的每一行数据,然后对数据进行保存或者处理
    ResultSet rs = null;

    try {
      Class.forName("com.mysql.jdbc.Driver");

      conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/temp_database", "root",
          "root");
      stmt = conn.createStatement();

      String sql = "select * from test_user";
      rs = stmt.executeQuery(sql);

      // 获取到ResultSet以后,就需要对其进行遍历,然后获取查询出来的每一条数据
      while (rs.next()) {
        int id = rs.getInt(1);
        String name = rs.getString(2);
        int age = rs.getInt(3);
        System.out.println("id=" + id + ", name=" + name + ", age=" + age);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
        }
        if (conn != null) {
          conn.close();
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }

  /**
   * 测试PreparedStatement
   */
  private static void preparedStatement() {
    Connection conn = null;
    /**
     * 如果使用Statement,那么就必须在SQL语句中,实际地去嵌入值,比如之前的insert语句
     * 
     * 但是这种方式有两个弊端:<br>
     * 第一,是容易发生SQL注入,SQL注入,简单来说,就是,你的网页的用户 在使用,比如论坛的留言板,电商网站的评论页面,提交内容的时候,可以使用'1
     * or 1',诸如此类的 非法的字符,然后你的后台,如果在插入评论数据到表中的时候,如果使用Statement,就会原封不动的
     * 将用户填写的内容拼接在SQL中,此时可能会发生对数据库的意外的损坏,甚至数据泄露,这种情况就叫做 SQL注入。
     * 
     * 第二,就是性能的低下,比如insert into test_user(name,age) values('张三',25) insert into
     * test_user(name,age) values('李四',26)
     * 其实两条SQL语句的结构大同小异,但是如果使用这种方式,在MySQL中执行SQL语句的时候,却需要对
     * 每一条SQL语句都实现编译,编译的耗时在整个SQL语句的执行耗时中占据了大部分的比例
     * 所以,Statement会导致执行大量类似SQL语句的时候的,性能低下。
     * 
     * 如果使用PreparedStatement,那么就可以解决上述的两个问题:
     * 1、SQL注入,使用PreparedStatement时,是可以在SQL语句中,对值所在的位置使用?这种占位符的
     * 使用占位符之后,实际的值,可以通过另外一份放在数组中的参数来代表。此时PreparedStatement会对
     * 值做特殊的处理,往往特殊处理后,就会导致不法分子的恶意注入的SQL代码失效。
     * 2、提升性能,使用PreparedStatement之后,其实结构类似的SQL语句,都变成一样的了,因为值的地方
     * 都会变成?,那么一条SQL语句,在MySQL中只会编译一次,后面的SQL语句过来,就直接拿编译后的执行计划
     * 加上不同的参数直接执行,可以大大提升性能。
     */
    PreparedStatement pstmt = null;

    try {
      Class.forName("com.mysql.jdbc.Driver");

      conn = DriverManager.getConnection(
          "jdbc:mysql://localhost:3306/temp_database?characterEncoding=utf8", "root", "root");

      // 第一个,SQL语句中,值所在的地方,都用问好代表
      String sql = "insert into test_user(name,age) values(?,?)";

      pstmt = conn.prepareStatement(sql);

      // 第二个,必须调用PreparedStatement的setX()系列方法,对指定的占位符设置实际的值
      pstmt.setString(1, "李四");
      pstmt.setInt(2, 26);

      // 第三个,执行SQL语句时,直接使用executeUpdate()即可,不用传入任何参数
      int rtn = pstmt.executeUpdate();

      System.out.println("SQL语句影响了【" + rtn + "】行。");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (pstmt != null) {
          pstmt.close();
          pstmt = null;
        }
        if (conn != null) {
          conn.close();
          conn = null;
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值