暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Unit02:JDBC核心API

amazingweiwei 2020-10-05
164

数据库连接池

1.定义:

数据库连接池是管理并发访问数据库连接的理想解决方案.

DriverManager管理数据库连接适合单线程使用,在多线程并发情况下,为了能够重用数据库连接,同时控制

并发连接总数,保护数据库,避免连接过载,一定要使用数据库连接池


2.DHCP连接池(之后试下其他开源实现方式)

1)导入 commons-dbcp2-2.8.0.jar 包,pom.xml依赖路径

  

        << span="">dependency>

            << span="">groupId>org.apache.commonsgroupId>

            << span="">artifactId>commons-dbcp2artifactId>

            << span="">version>2.8.0version>

        dependency>


2)DBCP连接池实现步骤:

1> 错误!未指定文件名。导入连接池jar包

2>创建连接池对象

3>设置数据库必须的链接参数

4>设置可选连接池管理

5>从连接池中获得活动的数据库连接

6>使用连接访问数据库

7>使用以后关闭数据库连接,这个关闭不是真的关闭连接,而是将使用过的连接归还给连接池.


3)将连接池封装为连接管理工剧烈 DBUtils

1> 配套参数配置文件 db.properties

# db.properties

jdbc.driver=oracle.jdbc.OracleDriver

jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl

jdbc.username=system

jdbc.password=123456

# parameter for BasicDataSource

initSize=2

maxActive=2

2>封装DBCP连接池codeDemo

package wei.jdbc;


import java.io.InputStream;

import java.sql.Connection;

import java.util.Properties;


import org.apache.commons.dbcp2.BasicDataSource;



/**

 * 将DBCP连接池封装为工具类

 */

public class DBUtils_1 {

    静态方法调用静态变量

    private static String driver;

    private static String url;

    private static String username;

    private static String password;

    private static int initSize;

    private static int maxActive;

    private static BasicDataSource ds;

    静态代码块加载静态资源并初始化静态变量

    static {

        ds = new BasicDataSource();

        Properties cfg = new Properties();

        try {

            读取db.properties 配制文件中的参数

            InputStream in = DBUtils_1.class.getClassLoader().getResourceAsStream("db.properties");

            /加载流(要加载流呀..20201005)

            cfg.load(in);;

            driver = cfg.getProperty("jdbc.driver");

            url = cfg.getProperty("jdbc.url");

            username = cfg.getProperty("jdbc.username");

            password = cfg.getProperty("jdbc.password");

            initSize = Integer.parseInt(cfg.getProperty("initSize"));

            maxActive = Integer.parseInt(cfg.getProperty("maxActive"));

            in.close();

            //初始化连接池对象

            ds.setDriverClassName(driver);

            ds.setUrl(url);

            ds.setUsername(username);

            ds.setPassword(password);

            ds.setInitialSize(initSize);

            ds.setMaxTotal(maxActive);

        } catch (Exception e) {

            e.printStackTrace();

            throw new RuntimeException();

        }

    }

   

    public static Connection getConnection() {

        try {

            /*

             * getConnection() 从连接池中获取重用的连接,如果连接池满了,则等待.

             * 如果有连接归还,则获取重用的连接

             */

            Connection conn = ds.getConnection();

            return conn;

        } catch (Exception e) {

            e.printStackTrace();

            throw new RuntimeException();

        }

    }

   

    public static void close(Connection conn) {

        if(conn!=null) {

            try {

                conn.close();

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

    }

}

执行计划

1.定义:

1)任何SQL都是先编译 "执行计划",再执行"执行计划"

2)数据库为了优化性能,在SQL形同时,会重用执行计划

1>执行计划编译较慢

2>重用执行计划可以提高数据库性能

3)数据库只在SQL语句完成一样时才重用相同的执行计划

1>如果SQL语句汇总有一个字符的更改,也会执行不同的执行计划

2>SQL中一个空格或者一个大小写不同也会创建不同的执行计划

2.PreparedStatement 对象

1)定义:PreparedStatement 对象用于执行带参数的预编译执行计划

2)作用:可以重复使用执行计划,提高DB效率

3)实现步骤:

1>将带参数的SQL发送到数据库创建执行计划

2>替换执行计划中的参数

3>执行 "执行计划",得到执行结果

4)codeDemo:演示预编译的SQL执行计划

package wei.jdbc.day02;


import java.sql.Connection;

import java.sql.PreparedStatement;


import wei.jdbc.DBUtils_1;


/**

 * 演示预编译的SQL执行计划

 */

public class Demo_PS_DML {

    public static void main(String[] args) {

        Connection conn = null;

        try {

            conn = DBUtils_1.getConnection();

            String sql = "INSERT INTO ismodelgp(id, symbol, secname) VALUES(?, ?, ?) ";

            PreparedStatement ps = conn.prepareStatement(sql);

            ps.setInt(1, 3);

            ps.setString(2, "600036");

            ps.setString(3, "招商银行");

            int n = ps.executeUpdate();

            System.out.println(n);

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtils_1.close(conn);

        }

    }

}

SQL注入

1.定义:

用户输入了含有SQL成分的参数,参数在拼接SQL时造成SQL语句的语义改变,从而改变SQL语句的执行计划,最终的执行结果就完全改变了.

2.如何避免SQL注入:

1)拦截用户输入的SQL成分(字符串校验)

2)固定执行计划,避免改变执行逻辑

3.SQL注入demo

1)输入用户名 tom 和密码 1' or '1' = '1 时候出现注入攻击现象

     使用 PS 就可以避免注入攻击,更新login方法如下:

package wei.jdbc.day02;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.Statement;

import java.util.Scanner;


import wei.jdbc.DBUtils_1;


publicclassDemo_SqlInjection {

    publicstaticvoid main(String[] args) {

        //获取用户输入

        Scanner scan =new Scanner(System.in);

        System.out.println("用户名:");

        String name = scan.nextLine();

        System.out.println("密码:");

        String pwd = scan.nextLine();

        //检查登录情况

//      boolean pass = login(name, pwd);

        boolean pass = loginPS(name, pwd);

        if(pass) {

            System.out.println("欢迎你!"+ name);

        }else {

            System.out.println("用户名或密码错误!");

        }

    }

   

    /** 通过PreparedStatement 固定执行计划,避免SQL注入 */

    publicstaticboolean loginPS(String name, String pwd) {

        String sql ="SELECT COUNT(*) ck FROM robin_user WHERE name = ? AND pwd = ? ";

        Connection conn =null;

        try {

            conn = DBUtils_1.getConnection();

            PreparedStatement ps =conn.prepareStatement(sql);

            ps.setString(1, name);

            ps.setString(2, pwd);

            ResultSet rs = ps.executeQuery();

            while(rs.next()) {

                int n = rs.getInt("ck");

                return n >=1;

            }

           

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtils_1.close(conn);

        }

       

        returnfalse;

    }

   

    /** 检查用户登录用户名、密码

     *

     *  1' or '1' = '1  ,sql中 and 优先级高于or, '1' = '1' 为 true,造成SQL语句的语义改变

     */

    publicstaticboolean login(String name, String pwd) {

        String sql ="SELECT COUNT(*) AS ck FROM robin_user WHERE name = \'"+name+"\' AND pwd = \'"+pwd+"\' ";

        Connection conn =null;

        try {

            conn = DBUtils_1.getConnection();

            Statement st = conn.createStatement();

            ResultSet rs = st.executeQuery(sql);

            while(rs.next()) {

                int n = rs.getInt("ck");

                return n >=1; //如果N>-1则登录成功

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtils_1.close(conn);

        }

        returnfalse;

    }

}

HomeWork

1.测试数据库连接池的使用

2.测试数据库连接池的并发性(用Rnunable实现)

3.封装连接管理工具类 DBUtils

4.利用PS实现数据库插入功能

5.利用PS实现数据库更新功能

6.利用PS实现数据库删除功能

7.利用PS实现数据库查询功能

8.完成SQL注入案例


文章转载自amazingweiwei,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论