JDBC Unit02 JDBC核心API

来源:互联网 发布:用python写小游戏 编辑:程序博客网 时间:2024/05/20 16:00

一.连接池(数据源)

1.不用连接池时的问题

  • 直接使用DriverManager时:
  • 每次调用它都会创建新连接,而没有复用连接
  • 它没有管理连接上限,当并发数大时可能导致数据库崩溃

2.连接池的作用

  • 连接池的作用就是解决上述问题:
  • 它能复用连接,提高效率
  • 它能管理连接上限,避免数据库崩溃

3.有哪些常用连接池

  • DBCP
  • C3P0

4.连接池的工作原理

  • 当创建连接池后,它会自动创建一批(配)连接放于池内
  • 当用户调用它时,它会给用户一个连接,并将连接标为占用
  • 当用户使用完连接后,将连接归还给连接池,它会将连接标为空闲
  • 若连接池发现连接快不够用时,它会再创建一批(配)连接
  • 若占用的连接达到数据库上限(配)时,连接池会让新用户等待
  • 在高峰期过后,连接池会关闭一批(配)连接

5.如何使用连接池(*)

  • sun规定了连接池的接口: DataSource
  • DBCP实现了连接池的接口: BasicDataSource

这里写图片描述

二.Statement和PreparedStatement

1.它们的联系(背)

  • 都是用来执行SQL的
  • PreparedStatement extends Statement

2.它们的区别(背)

  • Statement适合执行静态(无条件)SQL
  • PreparedStatement适合执行动态(有条件)SQL

3.Statement原理(理解)

这里写图片描述

4.PreparedStatement原理(理解)

这里写图片描述

5.PS可以避免注入攻击

这里写图片描述

三.结果集

1.关于结果集的指针

这里写图片描述

2.元数据

  • Meta: 根本、本质
  • MetaData: 数据的根本,即数据的概述信息
  • ResultSetMetaData: 对结果集的概述(描述)信息

案例代码

db.properties

注意:如果使用连接池,可以在这个文件中增加对连接池的相关设置:

连接池参数,常用参数有:

  • 初始连接数
  • 最大连接数
  • 最小连接数
  • 每次增加的连接数
  • 超时时间
  • 最大空闲连接
  • 最小空闲连接
# db connection parameters# key=valuedriver=oracle.jdbc.driver.OracleDriverurl=jdbc:oracle:thin:@192.168.201.227:1521:orcluser=openlabpwd=open123# datasource parametersinitSize=1maxSize=1

DBUtil.java

说明:DBUtil是DBTool的升级版,采用了连接池来管理连接。

package util;import java.io.IOException;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;import org.apache.commons.dbcp.BasicDataSource;/** *    1.DBUtil是DBTool的升级版 *    2.采用了连接池来管理连接 */public class DBUtil {    //DBCP连接池提供的实现类    private static BasicDataSource ds;    static {        Properties p = new Properties();        try {            //1.读取参数            p.load(DBUtil.class.getClassLoader()                .getResourceAsStream("db.properties"));            String driver = p.getProperty("driver");            String url = p.getProperty("url");            String user = p.getProperty("user");            String pwd = p.getProperty("pwd");            String initSize = p.getProperty("initSize");            String maxSize = p.getProperty("maxSize");            //2.创建连接池(1次)            ds = new BasicDataSource();            //3.向连接池设置参数            ds.setDriverClassName(driver);            ds.setUrl(url);            ds.setUsername(user);            ds.setPassword(pwd);            ds.setInitialSize(new Integer(initSize));            ds.setMaxActive(new Integer(maxSize));        } catch (IOException e) {            //异常的处理原则:            //1.记录日志(Log4j)            e.printStackTrace();            //2.能解决就解决(看开发规范)            //3.解决不了向上抛给调用者            //具体抛出哪种类型的异常看开发规范            throw new RuntimeException(                "加载配置文件失败", e);        }    }    public static Connection getConnection()         throws SQLException {        return ds.getConnection();    }    /**     * 1.目前我们使用连接都是连接池创建的     * 2.连接池重写了连接对象内部的close()     * 3.目前close()内部的逻辑是归还:     *      - 清除连接对象内部包含的所有数据     *      - 将连接对象状态设置为空闲态     */    public static void close(Connection conn) {        if(conn != null) {            try {                conn.close();            } catch (SQLException e) {                e.printStackTrace();                throw new RuntimeException(                    "关闭连接失败", e);            }        }    }}

Test.java

说明:这个类用于测试DBUtil

package jdbc;import java.sql.Connection;import java.sql.Date;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import org.junit.Test;import util.DBUtil;public class TestDay02 {    /**     * 1.测试DBUtil     * 2.执行DQL     *     查询部门ID为1的员工     */    @Test    public void test1() {        //假设页面传入的查询条件是        int deptno = 1;        Connection conn = null;        try {            conn = DBUtil.getConnection();            System.out.println(conn);            Statement smt = conn.createStatement();            String sql =                 "select * from emps_lhh "                + "where deptno="+deptno;            ResultSet rs = smt.executeQuery(sql);            while(rs.next()) {                System.out.println(rs.getInt("empno"));                System.out.println(rs.getString("ename"));            }        } catch (SQLException e) {            e.printStackTrace();            //测试代码可以适当简化异常处理        } finally {            DBUtil.close(conn);        }    }    /**     * 演示如何使用PS执行DML     */    @Test    public void test2() {        //假设页面传入的数据是        String ename = "曹操";        String job = "丞相";        int mgr = 0;        Date hiredate =             Date.valueOf("2017-01-22");        Double sal = 8000.0;        Double comm = 9000.0;        int deptno = 3;        Connection conn = null;        try {            conn = DBUtil.getConnection();            //写sql时条件用?代替            String sql =                 "insert into emps_lhh values("                + "emps_seq_lhh.nextval,"                + "?,?,?,?,?,?,?)";            //创建PS并传入sql,PS会立刻发送此sql            PreparedStatement ps =                 conn.prepareStatement(sql);            //先设置条件:给?赋值            //ps.set类型(?的序号,?的值)            ps.setString(1, ename);            ps.setString(2, job);            ps.setInt(3, mgr);            ps.setDate(4, hiredate);            ps.setDouble(5, sal);            ps.setDouble(6, comm);            ps.setInt(7, deptno);            //发送参数,执行SQL(计划)            ps.executeUpdate();        } catch (SQLException e) {            e.printStackTrace();        } finally {            DBUtil.close(conn);        }    }    /**     * 演示如何使用PS执行DQL     */    @Test    public void test3() {        //假设页面传入的查询条件是        int empno = 1;        Connection conn = null;        try {            conn = DBUtil.getConnection();            String sql =                 "select * from emps_lhh "                + "where empno=?";            PreparedStatement ps =                 conn.prepareStatement(sql);            ps.setInt(1, empno);            ResultSet rs = ps.executeQuery();            if(rs.next()) {                System.out.println(rs.getString("ename"));                System.out.println(rs.getString("job"));            }        } catch (SQLException e) {            e.printStackTrace();        } finally {            DBUtil.close(conn);        }    }    /**     * 使用PS执行查询语句,可以避免注入攻击     */    @Test    public void test4() {        //假设页面传入的参数是        String user = "zhangsan";        String pwd = "a' or 'b'='b";        Connection conn = null;        try {            conn = DBUtil.getConnection();            String sql =                 "select * from users_lhh "                + "where username=? "                + "and password=?";            PreparedStatement ps =                 conn.prepareStatement(sql);            ps.setString(1, user);            ps.setString(2, pwd);            ResultSet rs = ps.executeQuery();            if(rs.next()) {                System.out.println("登录成功");            } else {                System.out.println("账号或密码错误");            }        } catch (SQLException e) {            e.printStackTrace();        } finally {            DBUtil.close(conn);        }    }}

Test.java

演示如何从ResultSetMetaData中读取结果集相关的描述信息.
模拟转账业务.
批量添加员工(共108个,每批加50个)
添加部门及员工数据,添加员工时需要获取到部门的ID

package jdbc;import java.sql.Connection;import java.sql.Date;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import org.junit.Test;import util.DBUtil;public class TestDay03 {    /**     * 演示如何从ResultSetMetaData     * 中读取结果集相关的描述信息.     */    @Test    public void test1() {        //假设页面传入的查询条件是        int empno = 1;        Connection conn = null;        try {            conn = DBUtil.getConnection();            String sql =                 "select * from emps_lhh "                + "where empno=?";            PreparedStatement ps =                 conn.prepareStatement(sql);            ps.setInt(1, empno);            ResultSet rs = ps.executeQuery();            //获取结果集元数据,它是一个对象,            //内部封装了对结果集的描述信息.            ResultSetMetaData md = rs.getMetaData();            //多少列            System.out.println(md.getColumnCount());            //第1列的列名            System.out.println(md.getColumnName(1));            //第1列的类型的编号(常量)            System.out.println(md.getColumnType(1));            //第1列的类型的名称            System.out.println(md.getColumnTypeName(1));        } catch (SQLException e) {            e.printStackTrace();        } finally {            DBUtil.close(conn);        }    }    /**     * 模拟转账业务.     *      * 假设此时用户已经登录了网银,     * 并且已经输入了收款方账号和     * 转账的金额,点击了转账.     *      * 转账的步骤:     * 1.验证收款方账号是否存在(查询)     * 2.验证付款方余额是否够用(查询)     * 3.将付款方余额-N元(修改)     * 4.将收款方余额+N元(修改)     */    @Test    public void test2() {        //假设用户输入的信息如下        //付款方账号        String payId = "00001";        //收款方账号        String recId = "00002";        //转账的金额        double mny = 1000.0;        //转账是一个完整的业务流程,必须保证        //它的完整性,即该流程应处于一个事务        //之内,所以创建一个连接.        Connection conn = null;        try {            conn = DBUtil.getConnection();            //取消自动提交事务            conn.setAutoCommit(false);            //1.查询收款方账号并验证            String sql =                 "select * from accounts_lhh "                + "where id=?";            PreparedStatement ps =                 conn.prepareStatement(sql);            ps.setString(1, recId);            ResultSet rs = ps.executeQuery();            if(!rs.next()) {                throw new SQLException("收款方账号不存在");            }            double recMny = rs.getDouble("money");            //2.查询付款方余额并验证            String sql2 =                 "select * from accounts_lhh "                + "where id=?";            PreparedStatement ps2 =                 conn.prepareStatement(sql2);            ps2.setString(1, payId);            ResultSet rs2 = ps2.executeQuery();            double payMny = 0.0;            if(rs2.next()) {                payMny = rs2.getDouble("money");                if(payMny<mny) {                    throw new SQLException("余额不足");                }            }            //3.修改付款方余额            String sql3 =                 "update accounts_lhh set "                + "money=? where id=?";            PreparedStatement ps3 =                 conn.prepareStatement(sql3);            ps3.setDouble(1, payMny-mny);            ps3.setString(2, payId);            ps3.executeUpdate();            Integer.valueOf("断电了");            //4.修改收款方余额            String sql4 =                "update accounts_lhh set "                + "money=? where id=?";            PreparedStatement ps4 =                 conn.prepareStatement(sql4);            ps4.setDouble(1, recMny+mny);            ps4.setString(2, recId);            ps4.executeUpdate();            //转账是一个完整的过程,只需要在            //整个流程完成后,提交一次事务即可.            conn.commit();        } catch (Exception e) {            e.printStackTrace();            try {                conn.rollback();            } catch (SQLException e1) {                e1.printStackTrace();            }        } finally {            DBUtil.close(conn);        }    }    /**     *    批量添加员工(共108个,每批加50个)     */    @Test    public void test3() {        //这是一个完整的业务,只创建        //1个连接,提交1次事务        Connection conn = null;        try {            conn = DBUtil.getConnection();            conn.setAutoCommit(false);            String sql =                 "insert into emps_lhh values("                + "emps_seq_lhh.nextval,"                + "?,?,?,?,?,?,?)";            PreparedStatement ps =                 conn.prepareStatement(sql);            for(int i=1;i<=108;i++) {                //每次循环都将数据暂存到ps上                ps.setString(1, "好汉"+i);                ps.setString(2, "打劫");                ps.setInt(3, 0);                ps.setDate(4,                     Date.valueOf("2017-01-23"));                ps.setDouble(5, 6000.0);                ps.setDouble(6, 4000.0);                ps.setInt(7, 9);                ps.addBatch();                //每循环50次发送一次数据                if(i%50==0) {                    ps.executeBatch();                    //清空ps中的数据,以便于                    //暂存下一轮的数据                    ps.clearBatch();                }            }            //循环结束后,为了避免有零头(8),            //再单独批量发送一次数据.由于这            //是最后一次发送,所以不用清空ps了            ps.executeBatch();            conn.commit();        } catch (SQLException e) {            e.printStackTrace();            try {                conn.rollback();            } catch (SQLException e1) {                e1.printStackTrace();            }        } finally {            DBUtil.close(conn);        }    }    /**     * 添加部门及员工数据     * 添加员工时需要获取到部门的ID     */    @Test    public void test4() {        //假设页面传入的数据是        //部门        String dname = "财务部";        String loc = "杭州";        //员工        String ename = "郭嘉";        String job = "谋士";        int mgr = 0;        Date hiredate =             Date.valueOf("2017-01-23");        double sal = 6000.0;        double comm = 2000.0;        Connection conn = null;        try {            conn = DBUtil.getConnection();            conn.setAutoCommit(false);            //增加部门            String sql =                 "insert into depts values("                + "depts_seq.nextval,?,?)";            //参数2是一个数组,声明需要ps记住            //的字段的名称,ps在执行SQL时会            //记住这些字段的值.            PreparedStatement ps =                 conn.prepareStatement(                    sql, new String[]{"deptno"});            ps.setString(1, dname);            ps.setString(2, loc);            ps.executeUpdate();            //获取部门ID            //返回的结果集中存储了一条数据,            //该行数据包括我们让ps记录的所有字段.            ResultSet rs = ps.getGeneratedKeys();            System.out.println("rs"+rs);              //rsorg.apache.commons.dbcp.DelegatingResultSet@27efef64            rs.next();            //获取ps记录的字段时必须使用序号            int deptno = rs.getInt(1);            System.out.println("deptno"+deptno);  //deptno 4            //增加员工            String sql2 =                 "insert into emps values("                + "emps_seq.nextval,"                + "?,?,?,?,?,?,?)";            PreparedStatement ps2 =                 conn.prepareStatement(sql2);            ps2.setString(1, ename);            ps2.setString(2, job);            ps2.setInt(3, mgr);            ps2.setDate(4, hiredate);            ps2.setDouble(5, sal);            ps2.setDouble(6, comm);            ps2.setInt(7, deptno);            ps2.executeUpdate();            conn.commit();        } catch (SQLException e) {            e.printStackTrace();            try {                conn.rollback();            } catch (SQLException e1) {                e1.printStackTrace();            }        } finally {            DBUtil.close(conn);        }    }}
原创粉丝点击