JDBC、封装JDBC连接池、第三方连接池工具

JDBC简介

全称:Java DataBase Connection
译名:Java数据库连接

JDBC来源

JDBC的来源:
最早在Java提出连接数据库需求的时候,Java的做法是:Java根据不同数据库的特点,针对每一种数据库都提出了一套代码,在使用不同的数据库和Java进行连接的时候,使用不同的代码。
缺点:

  1. Java程序构建相当复杂,因为程序员要记住多种数据库连接代码,有多少种数据库,就要有多少种连接方式。
  2. Java代码的可重用性相当低,导致Java对数据库连接程序的开发效率下降,后来Java提出了新的思路:在Java中,我们提出了一套“标准(接口)”,将这套接口的实现交给不同的数据库厂商来完成。

优点:

  1. 程序员的工作压力下降,不管使用哪一种数据库连接,使用的接口类型都是一样的
  2. Java中DBC的代码重用度提高了,所有数据库的连接代码结构都是一样的,不同数据库厂商实现的Java中提供的“接口”,就构成了不同数据库的“驱动”。

通过代码实现JDBC

public class TestJDBC {
   
    public static void main(String[] args) {
   
        Connection conn = null;
        Statement stat = null;
        ResultSet set = null;
        
        try {
   
            //[1]加载JDBC驱动
//          Driver driver = new orcale.driver.jdbc.orcaleDriver();
            /*
             * Class.forName()方法会通过你提供的类路径找到这个类并加载进入虚拟机
             * 最重要的是,这个过程不需要实例化对象
             */
            Class.forName("oracle.jdbc.driver.OracleDriver");
            
            //[2]创建数据库连接对象
            String url = "jdbc:orcale:thin:@localhost:1521:orcl";
            String username = "数据库用户名";
            String password = "数据库密码";

            conn = DriverManager.getConnection(url, username, password);

            //[3]创建Statement对象,编写SQL语句
            String sql = "select * from employees";  //注意:此时SQL语句的结尾不要有字符的分号
            stat = conn.createStatement();

            //[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
            set = stat.executeQuery(sql);

            //[5]获取结果集中的数据,分析数据
            /*
             * 比较ResultSet和Iterator中的next()方法:
             * Iterator:
             *  在迭代器中,hasNext()方法返回boolean值,专门用来判断是否还有下一条记录
             *  但是不会移动记录的位指针
             *  迭代器中的next()方法,不仅负责向下移动位指针,还负责将下一条记录进行返回
             * 
             * ResultSet:
             *  ResultSet的next()方法即负责向下判断是否还存在下一条记录
             *  也负责在存在下一条记录的时候,移动位指针,返回下一条记录
             * 
             * ResultSet.next() = Iterator.hasNext() + Iterator.next()
             */
            while(set.next()) {
     //使用while循环负责遍历记录
                //使用下面的7条代码负责遍历一条记录中的7个字段
                System.out.print(set.getInt("emp_id") + ", ");  //emp_id
                System.out.print(set.getString("emp_name") + ", ");  //emp_name
                System.out.print(set.getString("emp_gender") + ", ");  //emp_gender
                System.out.print(set.getDouble("emp_salary") + ", ");  //emp_salary
                System.out.print(set.getDate("emp_birth") + ", ");  //emp_birth
                System.out.print(set.getDouble("commission_pct") + ", ");  //commission_pct
                System.out.println(set.getInt("dept_id"));  //dept_id
            }
        }catch(Exception e) {
   
            e.printStackTrace();
        }finally {
   
            //[6]关闭结果集对象,关闭Statement对象,关闭连接对象
            try {
   
                if(set != null) {
     //关闭ResultSet
                    set.close();
                }
            } catch (SQLException e) {
   
                e.printStackTrace();
            }
            try {
   
                if(stat != null) {
     //关闭Statement
                    stat.close();
                }
            } catch (SQLException e) {
   
                e.printStackTrace();
            }
            try {
   
                if(conn != null) {
     //关闭Connection
                    conn.close();
                }
            } catch (SQLException e) {
   
                    e.printStackTrace();
            }
        }
    }
}

JDBC的改进需求

  1. 注册JDBC驱动:
    将Driver驱动路径提取出来,当做一个独立的字符串使用。
  2. 创建数据库连接对象Connection对象:
    将数据库连接的URL、用户名、密码等信息写在一个外部文件中,每次连接数据库,创建Connection对象之前都读取这个外部文件,从外部文件动态的获取数据库连接信息。
  3. 创建Statement对象,编写SQL语句:
    Statement对象在执行SQL语句的时候,容易引起“SQL注入”,使用PreparedStatement对象替换Statement对象。
  4. 执行SQL,得到结果集ResultSet:
  5. 分析结果集,处理数据:
    当前查询结果集记录的方式,将每一条记录的每一个字段独立出来,互相之间没有关系,我们应该创建一个POJO类,将每一条记录封装为这个POJO类的一个对象,当前记录的字段取值就是POJO对象的属性值。
  6. 关闭结果集、关闭Statement、关闭连接对象Connection:
    关闭过程可以简化为关闭连接对象一个步骤。

JDBC改进的代码实现

Properties配置文件的读写:

  1. 创建一个.properties类型的文件
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:orcale:thin:@localhost:1521:orcl
jdbc.username=数据库用户名
jdbc.password=数据库密码
  1. 在Java代码中创建Properties对象,实现对外存资源文件的加载:
Properties pro = new Properties();
//将处于源码包中(src文件夹)中的配置文件以Properties流的方式进行返回,读入JVM内存中
InputStream is = TestJDBC.class.getResourceAsStream("/jdbc.properties");
//将流中保存的键值对信息读入Properties对象中,顺便解析成为键值对
pro.load(is);
  1. 从Properties对象中获取配置键值对:
//通过键找到值,找到的值就是配置信息
jdbcDriver = pro.getProperty("jdbc.driver");
jdbcUrl = pro.getProperty("jdbc.url");
jdbcUsername = pro.getProperty("jdbc.username");
jdbcPassword = pro.getProperty("jdbc.password");

使用PreparedStatement替换Statement对象:

  1. 演示Statement执行带有参数的SQL语句引起SQL注入:
//[3]创建Statement对象,编写SQL语句
String arg = "8000 or 1=1";  //这是一个查询参数
String sql = "select * from employees where emp_salary > " + arg;
stat = conn.createStatement();
//[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
set = stat.executeQuery(sql);
  1. 分析上述代码引起SQL注入的原因:
    1. 在查询条件中,我们强制注入了一个永真的条件。
    2. 现在SQL语句传递参数值的方式是拼接字符串,字符串本身没有识别SQL注入的功能。
  2. PreparedStatement对象的使用:
PreparedStatement stat = null;
//String arg = "8000 or 1=1";  //这是一个查询参数
String sql = "select * from employees where emp_salary > ?";  //在SQL语句中,所有的条件下,都使用?作为参数占位符
stat = conn.prepareStatement(sql);  //此时stat对象的来源已经是通过conn预编译得到
//[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
stat.setDouble(1, 8000.0);  //按照参数占位符的序号,为所有的?赋予参数
set = stat.executeQuery();  //注意:在使用PreparedStatement对象执行SQL语句的时候,执行方法中不要再次传递SQL语句
  1. 总结PreparedStatement的优点:
    1. PreparedStatement对SQL中的参数占位符进行预编译,所有传递进来的参数都当做一个整体看待。
      从根本上杜绝了SQL注入的原因——PreparedStatement不会引起SQL注入。
    2. PreparedStatement在对SQL执行预编译的时候,会将SQL语句存放在内存中,便于多次访问和执行这句SQL,不需要每次都重新加载SQL——PreparedStatement的SQL执行效率更高。

通过POJO对象封装查询结果:
1.回忆数据库中概念和Java中概念的对应关系:
在这里插入图片描述
2.代码实现:
创建和数据表表名、字段对应的POJO类:

public class Employee implements Serializable {
   
    private static final long serialVersionUID = -2675232990254926945L;

    //在POJO类当中,所有的字段类型推荐使用包装类类型
    private Integer empId;  //注意:在POJO类属性当中,所有的属性都不使用_(下划线),下划线是两个单词的界定,Java中的属性名使用驼峰命名法
    private String empName;
    private String empGender;
    private Double empSalary;
    private Date empBirth;
    private Double commissionPct;
    private Integer deptId;
	//空构造
    public Employee() {
   
        super();
    }
	//有参构造
    public Employee(Integer empId, String empName, String empGender, Double empSalary, Date empBirth,
            Double commissionPct, Integer deptId) {
   
        super();
        this.empId = empId;
        this.empName = empName;
        this.empGender = empGender;
        this.empSalary = empSalary;
        this.empBirth = empBirth;
        
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值