欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Javaweb入门 JDBC第一天

程序员文章站 2022-06-21 19:57:01
JDBC的定义和作用 DBC(Java DataBase Connectivity) Java数据库连接, 其实就是利用Java语言/程序连接并访问数据库的一门技术。 之前我们可以通过cmd或者navicat等工具连接并访问数据库,但是在企业开发中,我们更多的是通过程序连接并访问数据库。如果通过Ja ......

jdbc的定义和作用

  dbc(java database connectivity) java数据库连接, 其实就是利用java语言/程序连接并访问数据库的一门技术。

   之前我们可以通过cmd或者navicat等工具连接并访问数据库,但是在企业开发中,我们更多的是通过程序连接并访问数据库。如果通过java程序访问数据库,就必须要使用jdbc这门技术!!

jdbc访问数据库操作

  创建一个 jt_db 数据库,在库中创建一个account表,并插入三条记录,然后利用java程序查询出account表中所有的记录,并打印在控制台上。

快速人门程序了解:

创建java类并实现jdbc程序(大致分为六个步骤)

package com.tedu;

import java.sql.connection;
import java.sql.drivermanager;
import java.sql.resultset;
import java.sql.statement;

//jdbc快速入门程序
public class jdbcdemo1 {
    public static void main(string[] args) throws exception {
        /*
         * 通过java程序查询jt_db.account表中的所有记录
         * 将查询的结果输出到控制台上
         */
//        1.注册数据库
        class.forname("com.mysql.jdbc.driver");
//        2.获取数据库连接
        connection conn = drivermanager.getconnection(
                "jdbc:mysql://localhost:3306/jt_db", 
                "root", "root");
//        3.获取传输器
        statement stat = conn.createstatement();
//        4.发送sql语句到数据库执行,并返回执行结果
        string sql="select * from account";
        resultset r = stat.executequery(sql);
//        5.处理结果
//        r.next();判断是否指向记录,最开始指向表头的,用一次指向下一行记录,有记录返回true
        while (r.next()) {//进去循环,指向第一行数据,获取数据
            int id=r.getint("id");
            string name=r.getstring("name");
            double money=r.getdouble("money");
            system.out.println(id+", "+name+", "+money);
        }
//        6.释放资源
        r.close();
        stat.close();
        conn.close();
    }
}

jdbc快速入门细节

1.注册数据驱动

//注册数据库驱动
class.forname("com.mysql.jdbc.driver");

上面这行代码是根据传入的类的全路径(包名+类名)加载一个类到内存中。

在driver类中有一个静态代码块,静态代码块中包含着注册驱动的代码。

因此上面这行代码本身其实并不能注册驱动,但是可以让注册驱动的代码执行!

2.获取数据库连接

//获取数据库连接块
connection conn = drivermanager.getconnection(
                "jdbc:mysql://localhost:3306/jt_db", 
                "root", "root");

后面传入的两个参数分别是连接数据库的用户名和密码,这里不再过多描述

第一个参数是连接数据库的url地址(描述连接的是哪一个位置的哪一个库)。其中url地址的结构如下:

jdbc:mysql://localhost:3306/jt_db

————  —————— -----------

  协议名     主机名+端口    数据库的名字

其结构类似于平时访问的网址:

http://www.baidu.com:80/index.html?user=zhangfei

 

另外在url后面可以通过问号拼接参数:

jdbc:mysql:///jt_db?characterencoding=utf-8

characterencoding=utf-8 可以预防jdbc乱码

(可以避免通过jdbc往数据库插入中文数据时乱码

同时也可以避免通过jdbc从数据库查询数据时出现中文乱码问题)

3.statement传输器对象

stat.executequery( sql ) – 执行查询类的sql语句, 执行的结果是一个resultset对象, 其中包含了查询的结果

stat.executeupdate( sql ) – 执行增删改类型的sql语句, 执行的结果是一个int值, 表示影响的记录行数。

4.resultset结果集对象

resultset结果集其中包含了sql查询后的结果, 该对象上提供了遍历数据的方法和获取数据的方法:

(1)遍历数据行的方法

rs.next() – 将指向数据行的箭头往下挪动一行, 如果挪动一行后指向了一行记录, 方法将返回true, 否则返回false。

 

(2)获取数据的方法

rs.getint( colname )

rs.getstring( colname )

rs.getdouble( colname )

rs.getobject( colname )

...

5.释放资源

rs.close();

stat.close();

conn.close();

 

释放时遵循一个顺序, 越晚获取的越先关闭!!

jdbc增删改查

1、新增:往account表中插入一条新的记录,name "john"money3000

@test
    
    public void add() throws exception{
        /*
         * 新增:往account表中插入一条新纪录,name为"join",money为30000
         */
        class.forname("com.mysql.jdbc.driver");
        connection conn = drivermanager.getconnection(
                "jdbc:mysql://localhost:3306/jt_db", 
                "root", "root");
        statement stat = conn.createstatement();
        string sql="insert into account values (null,'john',3000)";
        int r = stat.executeupdate(sql);//返回影响的行数
        system.out.println("影响的行数:"+r);
        stat.close();
        conn.close();
    }

2修改:修改account表中name "john" 的记录,将金额改为1500

@test
    public void update() throws exception{
        /*
         * 修改account表中name为 "john" 的记录,将金额改为1500
         */
        connection conn = jdbcutil.getconn();
        statement stat = conn.createstatement();
        string sql="update account set money =1500 where     
                                 name='john' ";
        int r = stat.executeupdate(sql);
        system.out.println("影响行数:"+r);
        jdbcutil.close(conn, stat, null);
    }

3删除:删除account表中name为 "john" 的记录

@test
    public void delete() throws exception{
        /*
         * 删除:删除account表中name为 "john" 的记录
         */
        connection conn = jdbcutil.getconn();
        statement stat = conn.createstatement();
        string sql="delete from account where name='john'";
        int r = stat.executeupdate(sql);
        system.out.println("影响行数:"+r);
        jdbcutil.close(conn, stat, null);
    }

4、查询:查询account表中id1的记录

@test
    public void find() throws exception{
        /*
         * 查询account表中id为1的记录
         */
        connection conn = jdbcutil.getconn();
        statement stat = conn.createstatement();
        string sql="select * from account where id=1";
        resultset r = stat.executequery(sql);
//        while (r.next()) {
//            int id=r.getint("id");
//            string name=r.getstring("name");
//            double money=r.getdouble("money");
//            system.out.println(id+","+name+","+money);
//        }
        if(r.next()){
            int id=r.getint("id");
            string name=r.getstring("name");
            double money=r.getdouble("money");
            system.out.println(id+","+name+","+money);
        }
        jdbcutil.close(conn, stat, r);
    }

上面代码中调用了工具类中注册,连接数据库和释放资源的方法

package com.tedu.util;

import java.sql.connection;
import java.sql.drivermanager;
import java.sql.resultset;
import java.sql.sqlexception;
import java.sql.statement;

/** jdbc工具类 */
public class jdbcutil {
    /**
     * 获取数据库连接对象并返回
     * @return connection对象
     * @throws exception 
     */
    public static connection getconn() throws exception{
        //1.注册驱动
        class.forname( "com.mysql.jdbc.driver" );
        //2.获取连接
        connection conn = drivermanager.getconnection(
                "jdbc:mysql:///jt_db?characterencoding=utf-8", 
                "root", 
                "root");
        return conn;
    }
    
    /**
     * 释放jdbc程序中的资源
     * @param conn 连接对象
     * @param stat 传输器对象
     * @param rs 结果集对象
     */
    public static void close(connection conn, 
            statement stat, resultset rs){
        if(rs != null){
            try {
                rs.close();
            } catch (sqlexception e) {
                e.printstacktrace();
            } finally{
                rs = null;
            }
        }
        if(stat != null){
            try {
                stat.close();
            } catch (sqlexception e) {
                e.printstacktrace();
            } finally{
                stat = null;
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (sqlexception e) {
                e.printstacktrace();
            } finally{
                conn = null;
            }
        }
    }
}

模拟用户登录案例

创建loginuser类,提供mian方法和login方法

public static void main(string[] args) {

    /* 提示用户在控制台输入用户名和密码,并接收用户名和密码

     * 根据用户名和密码查询user表, 如果查询到记录, 则证明

     * 用户名密码正确, 模拟登录, 否则提示用户名密码错误!!*/

   

    scanner in = new scanner( system.in );

    //1.提示用户输入用户名和密码,并接收

    system.out.println("请登录...");

    system.out.println("请输入用户名:");

    string user = in.nextline();

    system.out.println("请输入密码:");

    string pwd = in.nextline();

   

    //2.调用login方法, 传入用户名和密码进行登录操作

    login( user, pwd );

}

/**

 * 根据用户名和密码进行登录

 * @param user 用户名

 * @param pwd 密码

 */

private static void login(string user, string pwd) {

    connection conn = null;

    statement stat = null;

    resultset rs = null;

    try {

       //1.注册驱动并获取连接

       conn = jdbcutil.getconn();

       //2.获取传输器并执行sql语句

       stat = conn.createstatement();

       string sql =

              "select * from user where username='"

               +user+"' and password='"+pwd+"'";

       system.out.println( sql );

       rs = stat.executequery( sql );

       //3.处理结果

       if( rs.next() ) {//用户名密码正确

           system.out.println("恭喜您登录成功!!");

       }else {

           system.out.println("登录失败! 用户名或密码不正确!!");

       }

    } catch (exception e) {

       e.printstacktrace();

    }

}

执行时输入:

请登录...
请输入用户名:
张飞'#'
请输入密码:

select * from user where username='张飞'#'' and password=''
恭喜您登录成功!!

或输入:

请登录...
请输入用户名:
张飞' or '1=1
请输入密码:

select * from user where username='张飞' or '1=1' and password=''
恭喜您登录成功!!

或输入:

请登录...
请输入用户名:
 
请输入密码:
' or '2=2
select * from user where username='' and password='' or '1=1'
恭喜您登录成功!!

以上在用户名或密码错误的情况下也能登录,就是sql注入攻击

sql注入攻击是一种常见的网络攻击方式,其产生的原因是:

由于后台的sql语句是拼接而来的, 其中的参数是用户提交过来的, 如果用户在提交参数时, 在参数中添加了一些sql关键字或者特殊符号, 就可能会导致sql语句语义的改变,从而导致一些意外的操作,比如用户名或密码错误也能登录成功!

解决方案:

(1)通过正则对用户提交的用户名或密码进行检查, 如果其中包含

 sql关键字或者特殊符号, 则提示用户名或密码输入不合法

(2)通过preparedstatement对象可以防止sql注入攻击!

防止sql注入攻击

preparedstatement对象是如何防止sql注入攻击的?

先将sql语句的骨架(包含问号占位符)发送给服务器, 让服务器编译并确定下来。

再将sql语句中的参数发送给服务器,由于前面服务器已经确定了sql语句(一旦确定就不能被改变),因此参数中即使再包含sql关键字或者特殊符号,也不会影响sql语句的语义,只会被当做普通的文本来对待!

/**

 * 根据用户名和密码进行登录

 * @param user 用户名

 * @param pwd 密码

 */

private static void login(string user, string pwd) {

    connection conn = null;

    preparedstatement stat = null;

    resultset rs = null;

    try {

       //1.注册驱动并获取连接

       conn = jdbcutil.getconn();

       //2.获取传输器并执行sql语句

       string sql = "select * from user where"

              + " username=? and password=?";

       stat = conn.preparestatement( sql );

       //设置sql参数(如果有?占位符)

       stat.setstring( 1 ,  user );

       stat.setstring( 2, pwd );

       //执行sql语句

       rs = stat.executequery( );//不要再传sql语句!

 

       //3.处理结果

       if( rs.next() ) {//用户名密码正确

           system.out.println("恭喜您登录成功!!");

       }else {

           system.out.println("登录失败! 用户名或密码不正确!!");

       }

    } catch (exception e) {

       e.printstacktrace();

    } finally {

       //4.释放资源

       jdbcutil.close(conn, stat, rs);

    }

}