JDBC学习

JDBC是一个访问各大数据库的接口,专为java程序访问数据库而出品,学习web开发,JDBC是必不可少的临门一脚,因为web系统基本都需要连接数据库。

1.原始jdbc访问数据库(没有封装过)

步骤:1.装载驱动程序 2.建立数据库连接 3.执行数据库语句 4.获取执行结果 5.清理环境

以下以book图书表的按类型查找类型为例子:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by *** on 2017/10/22.
 */
public class OriginalJDBC {
    private final static String DRIVEFORNAME = "com.mysql.jdbc.Driver";
    private final static String URL = "jdbc:mysql://localhost:3306/book";
    private final static String USERNAME = "root";
    private final static String PASSWORD = "1234";

    /**
     * 查找type="{}"的数据
     *
     * @return
     */
    public List<Book> findByType(String type) {
        //初始化
        Connection con = null;
        PreparedStatement pstmt = null;
        String sql = null;
        ResultSet rs = null;
        List<Book> bookList = new ArrayList<Book>();

        try {
            //装载驱动程序
            Class.forName(DRIVEFORNAME);
            //建立数据库连接
            con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            //编写sql,参数用?代替
            sql = "select * from bookta where type=?";
            //获得语句对象,承载sql语句
            pstmt = con.prepareStatement(sql);
            //设置参数
            pstmt.setString(1, type);
            //执行sql语句
            rs = pstmt.executeQuery();
            //获取执行结果
            while (rs.next()) {
                Book book = new Book();
                //数据库记录->实体对象
                book.setIsbn(rs.getString(1));
                book.setTitle(rs.getString(2));
                book.setType(rs.getString(3));
                book.setPrice(rs.getDouble(4));
                //对象加入集合
                bookList.add(book);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //finally代码块特点:抛出异常也会运行
            //负责关闭资源,先申请的资源的后关闭,此处代码有误,应该先关闭rs对象
            try {
                if (con != null) {
                    con.close();
                }
                if (pstmt != null) {
                    pstmt.close();
                }
                if (rs != null) {
                    rs.close();
                }
            } catch (Exception e1) {
                //ignore
            }
            return bookList;
        }
    }
}

亮点:(1).清理环境(关闭资源),无论是jdbc的哪一步骤出现了异常,代码总能使用finally代码块将已申请的资源释放掉,假如系统使用过程中出现了bug,就不会产生连接等资源的堆积,造成系统性能变差,适合在上线时候使用。

(2)与一步骤一try catch(写上通俗易懂的异常提醒)相比,此代码块将步骤全都放在一个try catch块内,异常提示能力虽然有待提高,但资源做到了创建一个关闭一个,一步骤一try catch并没有去关闭异常出现前的创建好的资源,一旦此处出现异常,数据访问一多,系统未释放的资源数变多,性能就变差,当然,一般是在开发阶段使用,服务器关闭资源就被释放了,不会出现这样情况。

测试:

public class Test {
    public static void main(String[] args) {
        //测试
        OriginalJDBC originalJDBC=new OriginalJDBC();
        List<Book> bookList =originalJDBC.findByType("文学");
        //遍历
        for(Book book:bookList){
            System.out.println(book.getTitle()+"这本书价格为"+book.getPrice());
        }
    }
}

2.sql注入

sql注入是使用拼接sql语句造成的一种数据库漏洞,“不法分子”改变sql语义来获取数据库信息,比如登录验证,select * from user where username="张三" and password="123" 种的username前台填成张三' or 1=1;-- ,这样下来or 1=1成了永真式,--后的密码成了注释,于是结果用户登录成功。

解决方案:使用preparedstatement,创建这个语句对象时需要传递sql语句,此时已经确定了sql语句,也不需要为String类型的字段加上单引号,相比statement更方便和安全。

程序:

/**
 * 测试sql注入
 */
public List<Book> findByTypeSQLInsert(String type) {
    //初始化
    Connection con = null;
    Statement statement = null;
    String sql = null;
    ResultSet rs = null;
    List<Book> bookList = new ArrayList<Book>();

    try {
        //装载驱动程序
        Class.forName(DRIVEFORNAME);
        //建立数据库连接
        con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        //编写sql
        sql = "select * from bookta where type='"+type+"'";
        //获得语句对象
        statement = con.createStatement();
        //执行sql语句
        rs = statement.executeQuery(sql);
        //获取执行结果
        while (rs.next()) {
            Book book = new Book();
            //数据库记录->实体对象
            book.setIsbn(rs.getString(1));
            book.setTitle(rs.getString(2));
            book.setType(rs.getString(3));
            book.setPrice(rs.getDouble(4));
            //对象加入集合
            bookList.add(book);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //finally代码块特点:抛出异常也会运行
        //负责关闭资源,先申请的资源的后关闭,此处代码有误,应该先关闭rs对象
        try {
            if (con != null) {
                con.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e1) {
            //ignore
        }
        return bookList;
    }
}

 

在此程序中使用statement对象,测试语句段如下:

//测试sql注入
System.out.println("测试sql注入");
//测试sql注入,数据库中其实没有type="爱情"依然能查询数据库
//select * from bookta where type='爱情' or 1=1,-- ';
bookList=originalJDBC.findByTypeSQLInsert("爱情' or 1=1;-- ");
for (int i = 0; i < bookList.size(); i++) {
 System.out.println(bookList.get(i).getTitle() + "价格为" + bookList.get(i).getPrice());
}

该程序仍能查询所有的书籍信息,网络上还有很多这样的sql注入,所以,开发系统时一定要使用preparedstatement对象,且要杜绝提供客户端删除表、限制删除记录等权限。

github源代码,点击转到github仓库处。喜欢的话请点个赞。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值