java之jdbc数据库连接技术

上面说到JDBC是一组接口组成的,下面我们就必须知道JDBC的核心API,也就是常用是哪些接口与类:

下面大致说一下执行流程:

然后我们看一个普通实例:

在写这个实例之前,我来说两点:

第一点:JDBC这一系列接口都是由相应厂商实现的,也就是说,我们想要用到这些已经做好的接口,就必须去导入相应厂商的jar包,这里我用的JDBC jar包是:

注意右键add as library才能作为库让我们调用。

 第二点:关于注册数据库驱动的问题,我们说了Driver这个类是我们必须要用到的,他可以帮助我我们注册驱动,源代码如下:

你看内部写了一个静态代码块,调用了驱动管理类的方法给我们注册驱动。

换句话说,我们可以这样来写:

Class.forname("com.mysql.jdbc.Driver");利用反射加载一个类对象,它的目的是加载这个类之后,调用静态代码块加载驱动。

JdbcDemo1.java:

package jdbc;


import com.mysql.jdbc.Driver;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcDemo1 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement state = null;
        try {
            //第一步注册驱动
            Driver driver = new Driver();
            //需要一个Properties来提供用户名与密码属性
            Properties properties = new Properties();
            properties.setProperty("user","root");//user固定的属性
            properties.setProperty("password","5201314");//password固定的属性
            //第二步得到连接对象
            conn = driver.connect("jdbc:mysql:///pxx",properties);//这个可以获取一个连接对象
            //然后创建一个执行的sql语句
            String sql = "update st5 set age = 520 where id = 1";
            state = conn.createStatement();
            int flag = state.executeUpdate(sql);
            if(flag == 1) {
                System.out.println("程序执行成功");
            } else {
                System.out.println("程序执行失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //注意资源的关闭
            if(state != null) {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

上面就是我更改了我数据库表st5的年龄:

原来表的数据:

 现在表的数据:

我们还可以有另外一种写法:

JdbcDemo2.java:

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcDemo2 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement state = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql:///pxx","root","5201314");
            //然后创建一个执行的sql语句
            String sql = "update st5 set age = 360 where id = 1";
            state = conn.createStatement();
            int flag = state.executeUpdate(sql);
            if(flag == 1) {
                System.out.println("程序执行成功");
            } else {
                System.out.println("程序执行失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}

上面也会执行成功,那么这个时候有个疑问,驱动在哪注册的?

我之前说了,DriverManager可以帮我们注册驱动:

先看一下它调用的连接函数:

内部要去调用了一个getConnection()函数,再次进入,看到下面这段代码:

 他会用内部一个Driver对象去调用connect方法,这个时候,Driver会加载到内存,自动注册驱动。

下面说一下Statement常用的两种查询语句:

 我们可以看到executeQuery(String sql) => 返回一个结果集ResultSet

这个ResultSet里面有一个next()方法:

下面再来说一下如何获取表中的各个字段信息:

 

 下面看一个类封装信息,任务就是把一个数据库中一张表每一条记录封装成一个对象,然后在存到集合里面。

先看我们的需要封装的表:

先来创建一个Emp类:

Emp.java

package domain;

import java.util.Date;

public class Emp {
    int id;
    String name;
    String gender;
    double salary;
    Date joinDate;
    int deptId;

    public Emp() {
    }

    public Emp(int id, String name, String gender, double salary, Date joinDate, int deptId) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.salary = salary;
        this.joinDate = joinDate;
        this.deptId = deptId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public Date getJoinDate() {
        return joinDate;
    }

    public void setJoinDate(Date joinDate) {
        this.joinDate = joinDate;
    }

    public int getDeptId() {
        return deptId;
    }

    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                ", salary=" + salary +
                ", joinDate=" + joinDate +
                ", deptId=" + deptId +
                '}';
    }
}

 再来看一个数据库操作类:

JdbcDemo3.java:

package jdbc;

import domain.Emp;

import java.sql.*;
import java.util.ArrayList;

public class JdbcDemo3 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement state = null;
        ArrayList<Emp> list = new ArrayList<Emp>();
        ResultSet res = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql:///pxx","root","5201314");
            //创建语句对象
            state = conn.createStatement();
            //执行sql
            res = state.executeQuery("select * from emp");
            Emp emp = null;
            while(res.next()) {
                int id = res.getInt("id");
                String name = res.getString("name");
                String gender = res.getString("gender");
                double salary = res.getDouble("salary");
                Date joinDate = res.getDate(5);
                int deptId = res.getInt(6);
                emp = new Emp();
                emp.setId(id);
                emp.setName(name);
                emp.setGender(gender);
                emp.setSalary(salary);
                emp.setJoinDate(joinDate);
                emp.setDeptId(deptId);
                list.add(emp);
            }

            //上面就把每条数据放到了集合中
            System.out.println(list);//直接输出一下集合
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if(res != null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(state != null) {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

下面看一下运行结果:

 上面的代码我们会看到比较浪费效率的一件事儿,就是每次我们链接数据库,我们都要获得输入链接URL,输入用户名,输入密码,获得连接对象,获得语句对象,那么有没有一种方法可以把这些常用的方法给封装起来,下次我们直接调用就可以了,不用重复写了。

那么这个时候,就要写一个数据库工具类:

把连接需要的属性放到配置文件中。把获取连接对象方法封装起来,把关闭资源封装起来。这两个类型的操作每次写是最费劲的。

先来看我们的配置文件,放在src下面:(最好是放在src下面),名字以properties结尾:

utils.properties:

然后来看我的JdbcUtils.java:

package utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    private static String url;
    private static String user;
    private static String password;

    //我们要从配置文件中加载信息,不可能就是我们不写连接程序,还要写找配置文件程序吧,直接静态代码
    //加载就处理
    static{
        Properties properties = new Properties();
        InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("utils.properties");
        try {
            properties.load(is);
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    public static void close(Connection conn, Statement state) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(state != null) {
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //假如有资源结果集要处理,需要关闭资源
    public static void close(Connection conn, Statement state, ResultSet res) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(state != null) {
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(res != null) {
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


}

 然后看我们测试文件JdbcDemo4.java:

package jdbc;

import utils.JdbcUtils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcDemo4 {
    public static void main(String[] args) {
        //得到连接对象
        Connection conn = null;
        Statement stmt = null;
        try {
           conn = JdbcUtils.getConnection();
           stmt = conn.createStatement();
           String sql = "update st5 set age = 321 where id = 1";
           int count = stmt.executeUpdate(sql);
           if(count > 0) {
               System.out.println("数据修改成功");
           } else {
               System.out.println("数据修改失败");
           }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(conn,stmt);
        }
    }
}

查一下数据库,明显修改成功:

 下面模拟一下从数据库查找账号与密码,然后登录服务器的一个过程:

这是我们从数据库找的一张表:

再次之前,我来说一说next()方法与nextline()方法的区别对吗

看一下模拟用户登录代码:

JdbcDemo4.java

package jdbc;


import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class JdbcDemo4 {
    public static void main(String[] args) {
        //得到连接对象
        Connection conn = null;
        Statement stmt = null;
        ResultSet res = null;
        try {
           conn = JdbcUtils.getConnection();
           stmt = conn.createStatement();
           Scanner sc = new Scanner(System.in);
           System.out.println("请输入用户名:");
           String user = sc.nextLine();
           System.out.println("请输入密码:");
           String password = sc.nextLine();
           //下面是一条错误的sql语句,是因为没有把输入当成字符串处理
         //String sql = "select * from user where username = " + user + "and password = " + password;
           String sql = "select * from user where username = '" + user + "' and password = '" + password + "'";
            System.out.println(sql);
           res = stmt.executeQuery(sql);
           if(res.next()) {
               System.out.println("登录成功");
           } else {
               System.out.println("登录失败");
           }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(conn,stmt,res);
        }
    }
}

上面只要用户名密码输入正确了,就会提示我们登录成功

但是,会出现一个问题就是sql注入,那么啥是sql注入问题:

就是通过欺骗mysql来构成一种合理的sql语句,比如下面:

看看是不是欺骗了MySQL,从而拿到了全部的用户信息。

那么通过我们的客户端,我们可以这样来写:

 写sql注入语句的时候,要注意的是,符合语法要求。

那么这个时候,我们就要引入一个特别安全的sql语句对象来执行sql

上面 PreparedStatement接口继承了Statement接口,也就是说数据库厂商帮我们实现了上面接口的所有方法。

下面说一下PreparedStatement执行原理:

然后说一下使用方法:

 直接上源代码:

JdbcDemo5.java

package jdbc;

import java.sql.*;
import java.util.Scanner;

public class JdbcDemo5 {
    public static void main(String[] args) {
        //得到连接对象
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet res = null;
        try {
            conn = JdbcUtils.getConnection();
           // stmt = conn.createStatement();
            //下面是一条错误的sql语句,是因为没有把输入当成字符串处理
            String sql = "select * from user where username = ? and password = ?";
            //注意得到PreparedStatement对象
            stmt = conn.prepareStatement(sql);
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String user = sc.nextLine();
            System.out.println("请输入密码:");
            String password = sc.nextLine();
            //通过占位符来控制参数
            stmt.setString(1,user);
            stmt.setString(2,password);//传入的就是一个字符串,你不可能在拼接or
            if(res.next()) {
                System.out.println("登录成功");
            } else {
                System.out.println("登录失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(conn,stmt,res);
        }
    }
}

c3po数据库连接池

数据库连接池解决的问题

频繁的创建数据库链接,消耗内存

下面是他需要的两个jar和一个配置文件

把配置文件拿过来看一下

c3p0-config.xml

<c3p0-config>
    <!--使用默认的配置读取连接池
    走了一个空参构造函数的配置
    -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test</property>
        <property name="user">root</property>
        <property name="password">5201314</property>

        <!--连接池参数-->
        <property name="initialPoolSize">5</property>
        <!--最大的连接数量-->
        <property name="maxPoolSize">10</property>
        <!--超时时间-->
        <property name="checkoutTimeout">3000</property>
    </default-config>

    <!--
    在构造ComPooledDataSource的时候,构造函数
    传入一个参数名字走指定配置项
    -->

    <name-config name="otherc3p0">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test</property>
        <property name="user">root</property>
        <property name="password">5201314</property>

        <!--连接池参数-->
        <property name="initialPoolSize">5</property>
        <!--最大的连接数量-->
        <property name="maxPoolSize">10</property>
        <!--超时时间-->
        <property name="checkoutTimeout">3000</property>
    </name-config>
</c3p0-config>

 这里说明两点

        第一点:配置文件名字是不能改动的,只能叫c3p0-config.xml这个名字

        第二点:配置里面的属性名字不能改动。

下面说一下关于连接数量问题:

 下面说一下druid连接池

                

 这个连接池与c3p0有一些不同的点就是,它的配置文件必须是properties,但是名字可以随便起,可以放到任何类目录下面

下面直接来看一下配置文件

它的做法就是通过工厂获取一个连接池对象

DataSource  ds = DruidSourceFatory.createDataSource(pro);

它的配置信息如下

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值