JDBC和DBCP

jdbc是Java Database Connectivity(java数据库连接)是一种用于执行sql语句的java api

示例源码(防注入、使用PrepareStatement):

首先要利用反射注册加载驱动,然后是建立连接,这个过程需要指明url(类似于ip,用于识别数据库的位置,其写法为jdbc:mysql://192.168.88.107:3306/Mrs_WuHo_O,其中jdbc表示协议、mysql表示子协议、192.168.88.107:3306是要链接到的主机和端口,最后是数据库的名字)、用户名、密码。这样,就建立好了连接。

下一步是创建并执行我们要做的sql语句,执行语句时,我们有两个类可以选择,一个是Statement,一个是PrepareStatement

二者的主要区别是

  1)语句不同,PreparedStatement需要预编译以及需要参数

  2)由于PreparedStatement有缓存区,所以效率更高

  3)由于PreparedStatement有缓存区,所以更安全,防止了注入(1=1)

 解释下什么是“注入”,如SQL串为“update student set name=\"jdbc update\" where id=6”,其中用户输入的是6,修改结果是

如果用户输入"6 or 2=2",则会出现该sql无论如何都会改变所有结果的危险。执行sql"update student set name=\"jdbc update\" where id=6 or 2=2"的后结果集为:

那么,为什么Preparestatement可以防止注入呢?这与Preparestatement的预编译有关,SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理,而不会作为一个SQL指令。也就真正将用户的输入不再存在当作“SQL指令”去执行,统一都作为值去对待。

所以,Preparestatement是优于Statement的,况且我们现在是略有水平对的开发人员了微笑微笑微笑,所以我们选用Preparestatement,

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


public class JdbcTest {
    public static String driverName ="com.mysql.jdbc.Driver";
    public static String connection_url = "jdbc:mysql://192.168.88.107:3306/tianliang";
    public static String userName = "root";
    public static String userPwd = "tianliangedu";

    public static void main(String[] args) {
        try {
            Class.forName(driverName);
            Connection dbConn = DriverManager.getConnection(connection_url, userName,
                    userPwd);

            String sql="update student set classname=\"计算机科学与技术1班\" where classname= ? ";
            PreparedStatement ps=dbConn.prepareStatement(sql);
            ps.setString(1,"计科1班 or 2=2");

            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DBCP数据库连接池:

为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。

其中要设置连接池中初始化连接个数,池中最大连接数和最小连接数、等待时间。

import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
public class DBCPTest {
    //声明连接池对象引用,方便其它线程去共享使用
    public static BasicDataSource dataSource=null;
    static {
        //1、初始化连接池对象
        dataSource = new BasicDataSource();
        // 2、为数据源实例指定必须的属性,用户名、密码、url、驱动名称等
        dataSource.setUsername("root");
        dataSource.setPassword("tianliangedu");
        dataSource.setUrl("jdbc:mysql://192.168.88.107:3306/tianliang");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        // 3、指定数据源的一些可选属性
        // 3.1、指定数据库连接池中初使化连接数的个数
        dataSource.setInitialSize(2);
        // 3.2、指定最大连接数:同一时刻可以同时向数据库申请的连接数
        dataSource.setMaxTotal(3);
        // 3.3、指定最小连接数:在数据库连接池中保存的最少的空闲连接的数量
        dataSource.setMinIdle(2);
        // 3.4、等待数据库连接池分配连接的最长时间。单位为毫秒。超出时间将抛出异常
        dataSource.setMaxWaitMillis(5*1000);
    }
    public static void main(String args[]) throws Exception{
        //用5个线程去测试获取和关闭连接
        for(int i=0;i<5;i++){
            new Thread(new ConnectionRunnable(dataSource)).start();
        }
    }
}
//定义线程runnable类,方便对线程池的测试
class ConnectionRunnable implements Runnable{
    private BasicDataSource basicDataSource;
    public ConnectionRunnable(BasicDataSource basicDataSource){
        this.basicDataSource=basicDataSource;
    }

    public void run(){
        //每个线程分别得到和关闭连接各10次
        for(int i=0;i<10;i++){
            try{
                //从连接池中拿到一个数据库连接
                Connection conn=basicDataSource.getConnection();
                System.out.println(conn);
                //获取链接池正在被使用的链接数量
                System.out.println("active="+basicDataSource.getNumActive());
                //获取链接池中空闲链接数量
                System.out.println("idle="+basicDataSource.getNumIdle());
                //将用完的数据库连接还回到连接池中,该close方法已被dbcp重写
                conn.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值