zoukankan      html  css  js  c++  java
  • Java笔记17

    JDBC简介

    • java程序访问数据库的标准接口
    • JDBC接口通过JDBC驱动实现真正对数据库的访问
    • 编写一套代码, 访问不同的数据库
    • App.class -> java.sql.* -> mysql-xxx.jar -> (TCP) -> mysql

    JDBC查询

    • java.sql.*放的是一组接口
    • 用哪个数据库, 就用哪个数据库的实现类
    • 某个数据库实现了JDBC接口的jar包称为JDBC依赖

    JDBC连接

    • Connection代表一个JDBC连接, 相当于Java程序到数据库的连接.
    • 打开一个Connection, 需要准备URL, 用户名, 口令
    • DriverManager会自动扫描classpath, 找到所有的JDBC驱动, 然后根据我们传入的URL自动挑选一个合适的驱动
    • JDBC是一种昂贵的资源, 使用后要及时释放, 使用try (resource)自动释放JDBC连接

    JDBC查询详解

    • 第一步: 使用Connection提供的createStatement()方法创建一个Statement对象, 用于执行一个查询;
    • 第二步: 执行Statement对象提供的executeQuery("SELECT * FROM students")并传入SQL语句. 查询执行并获得返回的结果集
    • 第三部: 反复调用ResultSetnext()方法并读取每一行结果
          try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
            System.out.println(conn);
            try (Statement stmt = conn.createStatement()) {
              System.out.println(stmt);
              try (ResultSet rs = stmt.executeQuery("SELECT id, name, gender FROM students WHERE gender='F'")) {
                System.out.println(rs);
                while (rs.next()) {
                  long id = rs.getLong(1); // 索引从1开始
                  System.out.println(id);
                }
              }
            }
          }
    

    SQL注入

    • 使用精心构造的字符串, 拼接出不同SQL.
    • PreparedStatement可以完全避免SQL注入
    • 始终使用?作为占位符, 并把数据连同SQL本身传给数据库, 保证每次传给数据库的SQL语句先沟通那个. 只是站位数据不同
    • 高效利用数据对查询的查询.
        String sql = "SELECT * FROM user WHERE lgoin=? AND pass=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1, name);
        ps.setObject(2, pass);
    
    • 必须首先调用setObject()设置每个占位符?的值, 最后仍然获取的仍然是ResultSet对象

    数据类型

    • JDBC定义了一组常量表示如何映射SQL数据类型, 经常用到的转换:

    • SQL数据类型 / Java数据类型

    • BIT,BOOL / boolean

    • INTEGER / int

    • BIGINT / long

    • REAL / float

    • FLOAT,DOUBLE / double

    • CHAR,VARCHAR / String

    • DECIMAL / BigDecimal

    • DATE / java.sqal.Date,LocalDate

    • TIME / java.sql.Time,LocalTime

    • 只有最新的JDBC驱动才支持LocalDateLocalTime

    JDBC更新

    插入

    • 使用PreparedStatement执行sql语句, 使用executeUpdate()

    • 返回成功插入的数量

    • 创建PreparedStatement时, 同时指定RETURN_GENERATED_KEYS关键字, 自增后就能返回, 驱动就能返回自增关键则了.

    • 返回的是多行成功值

    • 插入, 更新, 删除都是使用executeUpdate()

    • 只是使用的sql语句不同

    JDBC事务

    • 数据库事务具有ACID特性
    • 数据库从安全性考虑, 对事物进行了四种安全特性
    • 数据库事务, 保证程序结果正常
    • JDBC中执行事务, 就是多条sql包裹在一个数据库事务中
      Connection conn = openConnection();
      try {
        // 关闭自动提交
        conn.setAutoCommit(false);
        // 执行多个sql
        insert();
        update();
        delete();
        conn.commit();
      } catch (SQLException e) {
        // 回滚
        conn.rollback();
      } finally {
        conn.setAutoCommit(true);
        conn.close();
      }
    
    • 数据库默认使用REPEATABLE_READ

    JDBC-Batch

    • 一次性生成批量优惠卷等场景
    • 循环生成PreparedStatement效率低
    • 反复调用addPatch, 相当于给一个sql加上了多组参数, 变成多行sql
    • 因为是多行, 返回一个数组, 表示每一条影响的sql数量
    try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
        try (PreparedStatement ps = conn.prepareStatement(
            "INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)"
          ))
        {
          for (String name: names) {
            ps.setString(1, name);
            ps.setInt(2, 0); // gender
            ps.setInt(3, 4); // grade
            ps.setInt(4, 99); // score
            ps.addBatch(); // 添加到batch
          }
          int[] ns = ps.executeBatch();
          for (int n : ns) {
            System.out.println(n + " inserted.");
          }
        }
    }
    

    JDBC连接池

    • JDBC线程连接是昂贵的操作
    • jdbc线程池标准接口 javax.sql.DataSource
    • 创建DataSource是非常昂贵操作, 所以通常DataSource实例总是作为一个全局变量存储, 并贯穿整个应用程序
        config.setJdbcUrl(JDBC_URL);
        config.setUsername(JDBC_USER);
        config.setPassword(JDBC_PASSWORD);
        config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时 1s
        config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时 60s
        config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数 10
        DataSource ds = new HikariDataSource(config);
    
        try (Connection conn = ds.getConnection()) {
          // ...
        }
    
    • 第一次调用ds.getConnection()会先在连接池内部创建一个Connection
    • 调用conn.close()时, 并不会真的关闭, 释放到连接池中.
    • 再次调用getConnection()并不会创建, 而是返回空闲的连接
  • 相关阅读:
    IReport问题整理
    超出打开游标的最大数的原因和解决方案【131101】
    【131031】rel 属性 -- link标签中的rel属性,定义了文档与链接的关系
    【131031】html:hidden的使用
    <jsp:include>和<%@include file=""%>区别【131031】
    【131031】<meta http-equiv=...> 的功能
    【131031】asp.net <%%>&<%#%>&<%=%>&<%@%>&<%$%>用法区别
    python面向对象(类的成员及类方法)
    python网络编程知识体系
    python面向对象(类和对象及三大特性)
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/13300263.html
Copyright © 2011-2022 走看看