• JDBC学习笔记


    总结 JDBC知识点
    * 什么是JDBC
    标准,接口,驱动程序
    * JDBC编码步骤TCP协议
    * 一组接口
    DriverManager
    Connection
    Statement
    PreparedStatement
    ResultSet
    * 语句对象
    Statement
    PreparedStatement
    CallableStatement: 可以调用存储过程
    * 几个JDBC知识点
    *事务处理
    *批量处理
    *可滚动处理集
    *数据库端分页JDBC实现
    -------------------------------------------------------------

     

     

     

    01
    ================================================================
    1.JDBC的编码步骤
    1) 加载数据库驱动
    驱动程序:即是JDBC这组接口的实现类和其他功能类
    由数据库厂商提供

    导入mysql jar包

    2) 创建连接
    DriverManager 驱动管理器
    DriverManager提供一个静态方法,建立与数据库的连接
    getConnection(url,user,pwd)
    url:连接数据库地址
    jdbc:mysql://ip:3306/数据库名

    jdbc:主协议
    mysql:子协议
    ip:远程其他机器,就是具体的ip
    本机127.0.0.1或localhost

    3) 发送sql语句并执行

    Statement stmt = connection.createStatement();
    statement 表示语句对象
    int executeUpdate(String sql)
    用来发送insert update delete语句

    ResultSet executeQuery(String sql)
    用来发送select语句,返回结果集

    4) 关闭连接
    数据库软件同时支持的连接数是有限的,每一个连接都占有着数据库有限的资源,开启连接程序执行结束后
    必须及时释放资源,关闭连接
    close():关闭语句对象,关闭连接对象

    API:
    DriverManager:类.驱动管理器
    Connection getConnecrion(url,user,pwd);
    Connection:连接对象的接口
    Statement createStatement();
    Statement:语句对象的接口
    int executeUpdate(String sql);
    发送增删改查sql语句
    ResultSet executeQuery(String sql);
    发送查询sql语句

    2. *加载驱动
    *创建连接
    *发送sql语句
    *处理结果集(如果是查询)
    *关闭连接

    ResultSet:结果集对象,带有指针的一块内存区域
    boolean next();移动结果集指针,默认指针指向第一条记录之前,next()指向第一条记录,
    如果有记录,返回true,否则返回false
    getXXX(String columnName);获取字段值





    02
    ======================================================================================
    PreparedStatement 预处理语句对象
    是Statement的子接口
    * 避免sql注入
    * 提高多次执行同一条sql语句的效率(缓存)
    * sql 语句的可读性更好
    只要sql中需要拼接java变量,就使用PreparedStatement

    sql语句--->预编译---->执行计划

     

    PreparedStatement接口的使用:
    * sql语句中有java变量用?替代 ?作为占位符
    select * from user where username = ? and password = ?
    * 实例化
    实例化期间传sql
    PreparedStatement pstmt = conn.prepareStatement(sql);

    * 装配占位符?的值
    pstmt.setString(1,username);
    pstmt.setString(2,password);

    * 执行sql语句
    执行查询
    pstmt.excuteQuery();
    发送执行增删改查语句
    pstmt.excuteUpdate();


    ------------------------
    ******解析配置文件
    1.获取指向类路径属性文件的输入流
    InputStream in = 当前类.class.getClassLoader().getResourceAsStream("db.properties");
    prop.load(in);
    根据key取值
    String url = prop.getProperty("url");

    *****
    2.还可以用java.util.ResourceBundle解析加载配置文件
    ResourceBundle bundle = ResourceBundle.getBundle("db");
    String url = bundle.getString("url");

    ----------------------------------------------------
    *******连接池
    * 提高效率
    不需要对应所有请求,临时创建新的连接
    * 可以管理连接数

    *成熟的连接池组件
    DBCP(DataBase Connection Pool) 核心类(BasicDataSource)
    BasicDataSource dataSource = new BasicDataSource();

            //加载参数
            dataSource = new BasicDataSource();
            //读取数据
            ResourceBundle bundle = ResourceBundle.getBundle("db");
            String url = bundle.getString("jdbc.url");
            String username = bundle.getString("jdbc.username");
            String password = bundle.getString("jdbc.password");
            
            int initsize = Integer.parseInt(bundle.getString("jdbc.initialSize"));
            int maxactive = Integer.parseInt(bundle.getString("jdbc.maxActive"));
            int maxwait = Integer.parseInt(bundle.getString("jdbc.maxWait"));
            
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            
            //设置初始化连接数
            dataSource.setInitialSize(initsize);
            //设置最大连接数
            dataSource.setMaxActive(maxactive);
            //设置最大等待时间
            dataSource.setMaxWait(maxwait);

    db.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=root
    jdbc.initialSize=20
    jdbc.maxActive=100
    jdbc.maxWait=5000

     


    c3p0(不需要写代码读取配置文件,直接配置c3p0-config.xml就好了)
    DataSource dataSource = new ComboPooledDataSource("c3p0");

    //加载参数
            dataSource = new ComboPooledDataSource("c3p0");

    c3p0-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <c3p0-config>
    
      <named-config name="c3p0"> 
    
          <property name="user">root</property>
    
          <property name="password">root</property>
    
          <property name="driverClass">com.mysql.jdbc.Driver</property>
    
          <property name="jdbcUrl">jdbc:mysql://localhost:3306/login</property>
    
    <!--以上的user是数据库的用户,
        password是数据库的密码,driverClass是mysql的数据库驱动,jdbcUrl是连接数据库的url -->
    
           <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->
    
            <property name="acquireIncrement">5</property>
    
        <!--初始化时获取十个连接,取值应在minPoolSize与maxPoolSize之间 -->
    
            <property name="initialPoolSize">10</property>
    
        <!--连接池中保留的最小连接数 -->
    
            <property name="minPoolSize">10</property>
    
        <!--连接池中保留的最大连接数 -->
    
            <property name="maxPoolSize">50</property>
    
        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
    
            <property name="maxStatements">20</property> 
    
        <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
    
            <property name="maxStatementsPerConnection">5</property>
    
          </named-config>
    
    </c3p0-config>

     

    ------------------------------------------------------
    JDBC中的事务处理
    事务:                 

      一组操作的逻辑单元
      一组添加         一组删除    一组更新
    事务具备四个特性(ACID)
      ----原子性(atomicity):

            一个事务是一个不可分割的逻辑单元,一个事务中,所有操作要么成功要么失败(转账业务,一个减少一个增加金额)
      ----一致性(Consistency):

            事务执行的前后,保证数据的完整性
            完整性:完备性和正确性
            外键字段的值必须是引用其他主键字段的值
            (删除主表的数据,从表必须被修改或被删除)
      ----隔离性(Isolation):

            多个事务执行,事务之间互不干扰
            数据库软件都有默认的事务隔离级别
            隔离级别:
              串行化(serialize):多个事务操作同一个表数据,必须排队执行
              读已提交(read commited)
              读未提交
              可重复读
            李四 10000 事务没有提交
            张三 20000 脏数据
      ----持久性(Durability):

            事务一旦提交,对数据库数据的影响是永久的


    ***********数据库端事务的操作:


        事务开启: 执行第一条增删改sql语句,事务会自动开启
        事务结束: commit 提交事务
        rollback 回滚事务(撤销事务)

    *JDBC默认自动提交事务
          ------>boolean conn.getAutoCommit();//获取先前提交方式
    (批量删除)----->conn.setAutoCommit(false);//将jdbc的自动提交事务取消
           ------>conn.commit();//显示提交事务
           ------>(如果有异常)conn.rollback();//撤销事务
           ------>conn.setAutoCommit(boolean);//在连接放回连接池中之前,还原提交方式

    *注意:在MySQL中,就算commit()没写也会自动提交事务,但是在oracle中必须写commit()才会提交事务

    *结论:(什么时候用)当出现一组操作(多条insert,update,delete)的需求,必须关注事务

    例:

    String username1 = "zansan";
            String username2 = "lisi";
            double money = 10000;
            Connection conn = null;
            boolean autoCommit = false;
                try {
                    conn = JDBCUtils.getConnection();
                
                    //获取默认提交方式
                    autoCommit = conn.getAutoCommit();
                    conn.setAutoCommit(false);
                    //账户一减少
                    String sql = "update account set balance = balance-? where username = ?";
                    PreparedStatement pstmt = conn.prepareStatement(sql);
                    pstmt.setDouble(1, money);
                    pstmt.setString(2, username1);
                    pstmt.executeUpdate();
                    //账户二增加
                    String sql2 = "update account set balance = balance+? where username = ?";
                    pstmt = conn.prepareStatement(sql2);
                    pstmt.setDouble(1, money);
                    pstmt.setString(2, username2);
                    pstmt.executeUpdate();
                    //提交事务
                    conn.commit();
                    System.out.println("转账成功");
                    
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    try {
                        conn.rollback();
                    } catch (SQLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }finally{
                    conn.setAutoCommit(autoCommit);
                    JDBCUtils.close(conn);
                }

    ************
    03
    ============================================================================================
    1.批量处理(要加事务处理)(减少与数据库交互次数)
      *预处理语句对象PreparedStatement
      String sql = "delete from user where id = ?"
      PreparedStatement pstmt = conn.prepareStatement(sql);
    如果删除十条数据,与数据库交互10次
      for(int id : ids){
        pstmt.setInt(1,id);
        //将操作添加到语句列表中
        pstmt.addBatch();
        //pstmt.executeUpdata();
        //一次性缓冲一组数据
        在语句对象中维护了一个语句列表
      }
      //一次性执行一组操作
      pstmt.executeBatch();

    * addBatch(), 填充语句列表
    * executeBatch(),执行语句列表

    *******添加一万条数据

    public static void main(String[] args){
            Connection conn = null;
            boolean autocommit = false;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "insert into account(username,balance) values(?,?)";
                PreparedStatement pstmt = conn.prepareStatement(sql);
                autocommit = conn.getAutoCommit();
                conn.setAutoCommit(false);
                for (int i = 0; i <= 10000; i++) {
                    pstmt.setString(1, "小本"+i);
                    pstmt.setDouble(2, 1000+i);
                    pstmt.addBatch();
                    //每70个提交一次
                    if(i%70==0){
                        pstmt.executeBatch();
                        //清除语句列表
                        pstmt.clearBatch();
                    }
                }
                pstmt.executeBatch();
                conn.commit();
                System.out.println("执行成功");
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }finally{
                try {
                    conn.setAutoCommit(autocommit);
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                JDBCUtils.close(conn);
            }
            
            
        }
    }

     



    ---------------------------------------------
    2.可滚动结果集
    默认结果集指针总是从前往后滚动
    ResultSet rs = pstmt.executeQuery();
    rs.next();

    boolean next();从前往后滚
    boolean absolute(int row);将结果集指针绝对定位
    boolean previous();从后往前滚

    ---------------------------------------------
    3.JDBC分页查询(Mysql)
    分页
    两种分页方式:
    * 内存分页
    查询所有数据,存储在内存中
    * 数据库端分页(常用)
    查询需要的数据(与数据库多次交互)
    数据库(mysql)端分页:
    例如每页显示3条:
    查看第一页:1,2,3
    查看第二页:4,5,6
    查看第八页:22,23,24

    limit关键字:mysql专用分页查询关键字
    select id,username from user limit ?,?
    int perpage = 5;
    int page = 1;
    int begin = (page-1)*perpage

    *****分页查询

    public static void main(String[] args) {
            //每页显示的记录数
            int perpage = 5;
            //当前页
            int page = 4;
            Connection conn = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "select id,username,balance from account limit ?,?";
                PreparedStatement pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, (page-1)*perpage);
                pstmt.setInt(2, perpage);
                
                ResultSet rs = pstmt.executeQuery();
                while(rs.next()){
                    System.out.println(rs.getString("id")+" "+rs.getString("username")+" "+rs.getString("balance  5"));
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                JDBCUtils.close(conn);
            }
            
        }

     

    **************************************************************************

  • 相关阅读:
    Django学习路10_创建一个新的数据库,指定列名并修改表名
    设计模式_单例模式的懒汉式实例化
    设计模式_理解单例设计模式
    Django学习路9_流程复习
    Django学习路8_学生表和班级表级联并相互查询信息
    Django学习路7_注册app到能够在页面上显示app网页内容
    es6基础:类、继承、重写
    简单的下拉刷新
    callback&&callback()
    转 五大浏览器四大内核
  • 原文地址:https://www.cnblogs.com/syp172654682/p/8551153.html
Copyright © 2020-2023  润新知