为了账号安全,请及时绑定邮箱和手机立即绑定

JDBC常用对象

标签:
Java


主要作用:

注册驱动 实际开发中使用Class.forName("com.mysql,jdbc.Drive");这种方式,因为之前的方式会导致注册两次驱动

获得连接 Connection getConnection(String url,String username,String password)

url写法:jdbc:mysql://localhost:3306/jdbctest

jdbc 协议

mysql 子协议

localhost 主机名

3306 端口号

jdbctest 数据库名

如果连接的是本机,可以简写为jdbc:mysql:///jbdctest

Connection 连接对象

主要作用:

创建用来执行SQL语句的对象

Statement createStatement() 执行SQL语句,有SQL注入漏洞威胁

PrepareStatement prepareStatement(String sql) 预编译SQL语句,解决SQL注入

CallableStatement prepareCall(String sql) 执行SQL中的存储过程

事务的管理

setAutoCommit(boolean autoCommit) 设置事务是否自动提交

commit() 事务提交

rollback() 事务回滚

Statement 执行SQL

主要作用:

执行SQL语句

boolean execute(String sql) 执行SQL,执行查询语句返回true,否则返回false

ResultSet execute(String sql) 执行SQL中的查询语句

int executeUpdate(String sql) 执行SQL中的插入、更新、删除语句

执行批处理操作

addBatch(String sql) 添加到批处理

executeBatch() 执行批处理

clearBatch() 清空批处理

ResultSet 结果集

主要作用:

获取查询到的结果

next() 判断是否存在下一条记录

针对不同类型的数据可以使用getXXX()获取数据

getObject() 通用获取数据,可以获取任何类型的数据

JDBC的SQL注入漏洞问题

package com.kernel.test;

import org.junit.Test;

import java.sql.Connection;

import java.sql.ResultSet;

import java.sql.Statement;

/**

 * 演示JDBC注入漏洞

 */

public class JDBCDemo04 {

    @Test

    /**

     * 测试SQL注入

     */

    public void demo1() {

        //boolean result = login("aaa", "11");

        //boolean result = login("aaa' or '1=1", "5454545");

        boolean result = login("aaa' -- ", "sjjkhnjkhnk");

        System.out.println(result);

    }

    public boolean login(String username, String password) {

        Connection connection = null;

        Statement statement = null;

        ResultSet resultSet = null;

        try {

            connection = DBUtil.getConnection();

            statement = connection.createStatement();

            String sql = "select * from user where username='" + username + "' and password='" + password + "'";

            resultSet = statement.executeQuery(sql);

            if (resultSet.next()) {

                return true;

            } else {

                return false;

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtil.release(resultSet, statement, connection);

        }

        return false;

    }

}

我们来看下这是什么原因,有这样一行代码

boolean result = login("aaa' or '1=1", "5454545");

这时,sql就变成了这样

sql = "select * from user where username='aaa' or '1=1' and password='545445'";

SQL会首先判断and这个语句,and的结果为false,username='aaa',结果为true,true or false返回true

再来看第二条

sql "select * from user where username='aaa' -- and password='sjjkhnjkhnk'

-- 是注释的意思,意思就是注释后面的password=xxx,肯定返回true

如何解决呢

PrepareStatement是Statement的子接口,它的实例对象可以通过调用Connection.prepareStatement(sql)方法获得,相对于Statement对象而言:

PrepareStatement可以避免SQL注入漏洞的问题

Statement会使数据库频繁的编译SQL,可能造成数据库缓冲区溢出,而PrepareStatement可以对SQL进行预编译,提高数据库执行效率

PrepareStatement允许使用占位符替换SQL中的参数,简化编写

package com.kernel.test;

import org.junit.Test;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.Statement;

/**

 * 演示JDBC注入漏洞

 */

public class JDBCDemo04 {

    @Test

    /**

     * 测试SQL注入

     */

    public void demo1() {

        //boolean result = login("aaa", "11");

        //boolean result = login("aaa' or '1=1", "5454545");

        boolean result = logon("aaa' -- ", "sjjkhnjkhnk");

        System.out.println(result);

    }

    /**

     * 避免SQL注入漏洞

     * @param username

     * @param password

     * @return

     */

    public boolean logon(String username, String password) {

        Connection connection = null;

        PreparedStatement preparedStatement = null;

        ResultSet resultSet = null;

        try {

            connection = DBUtil.getConnection();

            String sql = "select * from user where username=? and password=?";

            preparedStatement = connection.prepareStatement(sql);

            preparedStatement.setString(1, username);

            preparedStatement.setString(2, password);

            resultSet = preparedStatement.executeQuery();

            if (resultSet.next()) {

                return true;

            } else {

                return false;

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtil.release(resultSet, (Statement) preparedStatement, connection);

        }

        return false;

    }

    /**

     * 产生SQL注入漏洞

     *

     * @param username

     * @param password

     * @return

     */

    public boolean login(String username, String password) {

        Connection connection = null;

        Statement statement = null;

        ResultSet resultSet = null;

        try {

            connection = DBUtil.getConnection();

            statement = connection.createStatement();

            String sql = "select * from user where username='" + username + "' and password='" + password + "'";

            resultSet = statement.executeQuery(sql);

            if (resultSet.next()) {

                return true;

            } else {

                return false;

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtil.release(resultSet, statement, connection);

        }

        return false;

    }

}

为什么使用它就可以避免SQL注入漏洞呢?那是因为创建对象的时候就将sql传递进去,并进行了预编译,即使后面通过变量传递了关键字进来,也会认为这是字符串

数据库连接池

连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用

应用程序直接获得链接的缺点

用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗较大的资源,创建时消耗的事件也比较长,在高并发业务场景下,如果采用这种方式获得连接,极大浪费数据库的资源,并且容易造成数据库服务器内存溢出

那么连接池是怎么解决这个问题的呢

连接池中默认存放了若干个数据库连接对象,当用户请求与数据库进行连接时,直接从数据库中取出,当用户完成操作需要释放数据库连接资源时,销毁的连接回到连接池继续等待下一次用户的请求

C3P0的使用

package com.kernel.test;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import org.junit.Test;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

/**

 * 演示连接池

 */

public class DataSourseDemo01 {

    @Test

    /**

     * 手动设置连接池

     */

    public void demo1() {

        //获得连接

        Connection connection = null;

        PreparedStatement preparedStatement = null;

        ResultSet resultSet = null;

        try {

            //创建连接池

            ComboPooledDataSource dataSource = new ComboPooledDataSource();

            //设置连接池参数

            dataSource.setDriverClass("com.mysql.jdbc.Driver");

            dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/jdbctest");

            dataSource.setUser("root");

            dataSource.setPassword("123456");

            dataSource.setMaxPoolSize(20);

            connection = dataSource.getConnection();

            String sql = "select * from user";

            preparedStatement = connection.prepareStatement(sql);

            resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {

                System.out.println(resultSet.getInt("uid") + "\t"

                        + resultSet.getString("username") + "\t"

                        + resultSet.getString("password") + "\t"

                        + resultSet.getString("name"));

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DBUtil.release(resultSet, preparedStatement, connection);

        }

    }

    @Test

    /**

     * 读取配置文件设置连接池,默认读取src目录下的c3p0-config.xml文件

     */

    public void demo2() {

        //获得连接

        Connection connection = null;

        PreparedStatement preparedStatement = null;

        ResultSet resultSet = null;

        try {

            //创建连接池

            connection = DBUtil.getConnection();

            String sql = "select * from user";

            preparedStatement = connection.prepareStatement(sql);

            resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {

                System.out.println(resultSet.getInt("uid") + "\t"

                        + resultSet.getString("username") + "\t"

                        + resultSet.getString("password") + "\t"

                        + resultSet.getString("name"));

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            DButil2.release(resultSet, preparedStatement, connection);

        }

    }

}

编写C3P0的配置文件

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>

  <default-config>

    <property name="driverClass">com.mysql.jdbc.Driver</property>

    <property name="jdbcUrl">jdbc:mysql:///jdbctest</property>

    <property name="user">root</property>

    <property name="password">123456</property>

    <property name="initialPoolSize">5</property>

    <property name="maxPoolSize">20</property>

  </default-config>

</c3p0-config>

©著作权归作者所有:来自51CTO博客作者灰白世界的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消