JAVA语言之JDBC
小标 2019-04-03 来源 : 阅读 982 评论 0

摘要:本文主要向大家介绍了JAVA语言之JDBC,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言之JDBC,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

JAVA语言之JDBC

JDBC常用对象


DriverManager 驱动管理类


主要作用:



  • 注册驱动 实际开发中使用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>

   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程