Java_JDBC

JDBC:用于执行SQL语句的java API,为多种数据库提供统一的访问,不需要具体了解每种数据库的驱动的写法,只需要了解JDBC的接口规范,每种数据库的具体驱动都需要实现JDBC的规范

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

jdbc程序运行完后,必须释放程序在运行过程中,创建的那些与数据库交互的对象。ResultSet、Statement、Connection对象:Connection是数据库的连接对象,往往会有一个最大的访问个数,如果没有把对象及时释放掉,可能导致别人无法访问数据库

在这里插入图片描述

import com.mysql.jdbc.Driver;
import org.junit.Test;

import java.sql.*;

public class JDBCDemo1 {
    @Test
    public void demo1(){
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        //1.加载驱动
        try {
           // DriverManager.registerDriver(new Driver());会导致驱动注册两次,源代码中静态代码块包含注册驱动的语句,当Driver类被加载时会注册驱动
            //加上以上语句手动注册一次,会注册驱动两次
            Class.forName("com.mysql.jdbc.Driver");//加载Driver类,类一旦被加载,就会执行静态代码块,注册驱动

        //2.获得连接
            conn=DriverManager.getConnection("jdbc:mysql:///jdbctest","root","1984");
        //3.创建执行SQL语句的对象,并且执行SQL
            //3,1创建执行SQL的对象
            String sql="select * from user";
            stmt=conn.createStatement();
            //3.2执行SQL语句
             rs=stmt.executeQuery(sql);
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                String name=rs.getString("name");
                System.out.println(uid+" "+username+" "+password+" "+name);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //为了保证程序异常时,仍然可以正确释放资源,将释放资源放到finally代码块内(不管是否发生异常都会执行)
            //4.释放资源
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                  e.printStackTrace();
                }
                rs=null;

            }

            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt=null;

            }

            if(conn!=null){
                try {
                    conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn=null;//手动置为null,垃圾回收机制会更早地回收对象

            }
        }
    }
}

JDBC的增删改查:增删改操作基本一致

import org.junit.Test;

import java.sql.*;

public class JDBCDemo2 {
    //增删改操作基本类似
    @Test
    /**
     * 保存操作
     */
    public void demo1() {
        Connection conn = null;
        Statement stmt = null;
        //1.加载驱动
        try {
            // DriverManager.registerDriver(new Driver());会导致驱动注册两次,源代码中静态代码块包含注册驱动的语句,当Driver类被加载时会注册驱动
            //加上以上语句手动注册一次,会注册驱动两次
            Class.forName("com.mysql.jdbc.Driver");//加载Driver类,类一旦被加载,就会执行静态代码块,注册驱动

            //2.获得连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8", "root", "1984");
            //3.创建执行SQL语句的对象,并且执行SQL
            //3,1创建执行SQL的对象
            String sql = "insert into user values (null,'eee','123','张三')";
            stmt = conn.createStatement();
            //3.2执行SQL语句
            int i = stmt.executeUpdate(sql);//返回所影响的行数,i>0说明操作成功
            if (i > 0) {
                System.out.println("保存成功!");
            }
            } catch(Exception e){
                e.printStackTrace();
            }finally{
                //为了保证程序异常时,仍然可以正确释放资源,将释放资源放到finally代码块内(不管是否发生异常都会执行)
                //4.释放资源

                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    stmt = null;

                }

                if (conn != null) {
                    try {
                        conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    conn = null;//手动置为null,垃圾回收机制会更早地回收对象

                }
            }

        }


    @Test
    /**
     * 修改操作
     */
    public void demo2() {
        Connection conn = null;
        Statement stmt = null;
        //1.加载驱动
        try {
            // DriverManager.registerDriver(new Driver());会导致驱动注册两次,源代码中静态代码块包含注册驱动的语句,当Driver类被加载时会注册驱动
            //加上以上语句手动注册一次,会注册驱动两次
            Class.forName("com.mysql.jdbc.Driver");//加载Driver类,类一旦被加载,就会执行静态代码块,注册驱动

            //2.获得连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8", "root", "1984");
            //3.创建执行SQL语句的对象,并且执行SQL
            //3,1创建执行SQL的对象
            String sql = "update user set username='qqq',password='234',name='刘三' where uid=4";
            stmt = conn.createStatement();
            //3.2执行SQL语句
            int i = stmt.executeUpdate(sql);//返回所影响的行数,i>0说明操作成功
            if (i > 0) {
                System.out.println("修改成功!");
            }
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            //为了保证程序异常时,仍然可以正确释放资源,将释放资源放到finally代码块内(不管是否发生异常都会执行)
            //4.释放资源

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;

            }

            if (conn != null) {
                try {
                    conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;//手动置为null,垃圾回收机制会更早地回收对象

            }
        }

    }
    @Test
    /**
     * 删除操作
     */
    public void demo3() {
        Connection conn = null;
        Statement stmt = null;
        //1.加载驱动
        try {
            // DriverManager.registerDriver(new Driver());会导致驱动注册两次,源代码中静态代码块包含注册驱动的语句,当Driver类被加载时会注册驱动
            //加上以上语句手动注册一次,会注册驱动两次
            Class.forName("com.mysql.jdbc.Driver");//加载Driver类,类一旦被加载,就会执行静态代码块,注册驱动

            //2.获得连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8", "root", "1984");
            //3.创建执行SQL语句的对象,并且执行SQL
            //3,1创建执行SQL的对象
            String sql = "delete from user where uid=7";
            stmt = conn.createStatement();
            //3.2执行SQL语句
            int i = stmt.executeUpdate(sql);//返回所影响的行数,i>0说明操作成功
            if (i > 0) {
                System.out.println("删除成功!");
            }
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            //为了保证程序异常时,仍然可以正确释放资源,将释放资源放到finally代码块内(不管是否发生异常都会执行)
            //4.释放资源

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;

            }

            if (conn != null) {
                try {
                    conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;//手动置为null,垃圾回收机制会更早地回收对象

            }
        }

    }

    @Test
    /**
     * 查询所有记录/一条记录
     */
    public void demo4() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs=null;
        //1.加载驱动
        try {
            // DriverManager.registerDriver(new Driver());会导致驱动注册两次,源代码中静态代码块包含注册驱动的语句,当Driver类被加载时会注册驱动
            //加上以上语句手动注册一次,会注册驱动两次
            Class.forName("com.mysql.jdbc.Driver");//加载Driver类,类一旦被加载,就会执行静态代码块,注册驱动

            //2.获得连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8", "root", "1984");
            //3.创建执行SQL语句的对象,并且执行SQL
            //3,1创建执行SQL的对象
            String sql = "select * from user";
            //String sql="select * from user where uid=2";//一条记录
            stmt = conn.createStatement();
            //3.2执行SQL语句
            rs=stmt.executeQuery(sql);
            //if(rs.next()){//一条记录
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                String name=rs.getString("name");
                System.out.println(uid+" "+username+" "+password+" "+name);

            }
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            //为了保证程序异常时,仍然可以正确释放资源,将释放资源放到finally代码块内(不管是否发生异常都会执行)
            //4.释放资源

            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;

            }

            if (conn != null) {
                try {
                    conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;//手动置为null,垃圾回收机制会更早地回收对象

            }

            if (rs != null) {
                try {
                    rs.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;//手动置为null,垃圾回收机制会更早地回收对象

            }
        }

    }
}

抽取重复代码封装成工具类(使用静态成员)

import jdbc.utils.JDBCUtils;
import org.junit.Test;

import java.sql.Connection;
import java.sql.Statement;

public class JDBCDemo3 {
    @Test
    /**
     * 保存记录
     */
    public void demo(){
        Connection conn=null;
        Statement stmt=null;
        try {
            //获得连接
            conn= JDBCUtils.getConnection();
            //创建执行SQL语句的对象
            stmt=conn.createStatement();
            String sql="insert into user values(null,'fff','123','王四')";
            int i=stmt.executeUpdate(sql);
            if(i>0){
                System.out.println("保存成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.release(conn,stmt);
        }

    }
}
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC的工具类,想修改参数时,需要修改工具类的源代码,所以将参数提取到配置文件中,在工具类中只需要解析配置文件,在配置文件中修改参数
 */

public class JDBCUtils {
    //static final,全局变量,随着类加载而产生,在程序运行过程中不允许被修改,修饰配置信息
    private static final String driverClass;
    private static final String url;
    private static final String username;
    private static final String password;

    static{//静态代码块,无论类实例多少次,只执行一次,只能调用静态成员
        //加载属性文件并解析
        Properties props=new Properties();
        //如何获得属性文件的输入流
        //通常使用类的加载器的方式进行获取:FileInputStream("src/jdbc.properties"):在java项目中可行,Web项目不可行,没有src路径
        InputStream inputStream=JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
        try {
            props.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        driverClass="com.mysql.jdbc.Driver";
//        url="jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8";
//        username="root";
//        password="1984";
        driverClass=props.getProperty("driverClass");
        url=props.getProperty("url");
        username=props.getProperty("username");
        password=props.getProperty("password");
    }
    /**
     * 注册驱动的方法
     */
    public static void loadDriver() throws ClassNotFoundException {
        Class.forName(driverClass);
    }

    /**
     * 获得连接的方法
     * 静态方法,静态方法不能直接访问同一个类中的非静态成员,只能直接调用同一个类中的静态成员
     * 静态方法中不能使用this,this代表当前类实例,static代表类共享冲突,静态变量与静态方法属于一类,可直接访问
     * 通过对象实例化后,对象.成员方法的方式访问非静态成员
     */
    public static Connection getConnection() throws Exception {
        loadDriver();
        Connection conn= DriverManager.getConnection(url, username, password);
        return conn;
    }
    /**
     * 资源释放
     */
    public static void release(Connection conn, Statement stmt){
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;

        }

        if (conn != null) {
            try {
                conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;//手动置为null,垃圾回收机制会更早地回收对象

        }
    }

    public static void release(Connection conn, Statement stmt, ResultSet rs){

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;

        }

        if (conn != null) {
            try {
                conn.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;//手动置为null,垃圾回收机制会更早地回收对象

        }

        if (rs != null) {
            try {
                rs.close();//遵循晚创建,早释放,虽然释放了,但还没有被垃圾回收机制回收掉
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;//手动置为null,垃圾回收机制会更早地回收对象

        }
    }


}

配置文件

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8
username=root
password=1984

SQL注入的漏洞:一个网站需要登陆的功能,需要输入用户名和密码进行登陆,SQL注入漏洞是指已知用户名,不知道密码的情况下,也可以登陆到系统中,对账号进行破坏,原因:在输入用户名时输入了SQL语句的关键字

import jdbc.utils.JDBCUtils;
import org.junit.Test;

import java.sql.*;

/**
 * 演示JDBC注入的漏洞
 */

public class JDBCDemo4 {
    @Test
    /**
     * 测试SQL注入漏洞的方法:注入漏洞,在输入用户名时输入了SQL语句的关键字
     */
    public void demo(){
        //已知用户名,对账号进行破坏,显示登陆成功
        //boolean flag=JDBCDemo4.login("aaa' or '1=1","111hdjgjio");//输入了SQL的关键字or
        //String sql="select * from user where username = 'aaa' or '1=1'and password ='111hdjgjio'";//true or false为true
        //boolean flag=JDBCDemo4.login("aaa' -- ","111hdjgjio");
        //String sql="select * from user where username = 'aaa' -- 'and password ='111hdjgjio'";//--是注释,后面被注释掉了
       boolean flag=JDBCDemo4.login("aaa","111");
        if(flag)
            System.out.println("登陆成功");
        else
            System.out.println("登陆失败");
    }
    /**
     * 判断是否登陆成功
     * 根据输入的用户名和密码到数据库中查询,查询到了就返回,没查询到则登陆失败(JDBC的查询操作)
     */
    public static boolean login(String username,String password){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs=null;
        boolean flag=false;
        try {
            conn = JDBCUtils.getConnection();
            //创建执行SQL的语句
            stmt = conn.createStatement();
            //编写SQL语句
            String sql="select * from user where username = '" +username +"'and password ='"+password+"'";
            //执行SQL语句
            rs=stmt.executeQuery(sql);
            //判断结果集中是否有数据(查询到了)
            if(rs.next()){
                flag=true;
            }
            else
                flag=false;
        } catch(Exception e){
            e.printStackTrace();
        }finally{
           JDBCUtils.release(conn,stmt,rs);
        }
        return flag;


    }
}

SQL注入漏洞的解决:根本在SQL语句的拼接上,Statement对象执行SQL语句时,SQL语句是字符串拼接的,因此不能使用Statement对象,而使用PreparedStatement(预处理对象):使用占位符将SQL语句中变量的地方占住,SQL语句格式固定,再传来的SQL的关键字也不识别了,将关键字当作普通的字符串处理

在这里插入图片描述

/**
 * 避免SQL注入漏洞的方法
 */
public static boolean login2(String username, String password) {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    boolean flag=false;

    try {
        conn = JDBCUtils.getConnection();
        //编写SQL语句
        String sql = "select * from user where username = ? and password =?";
        //预处理SQL
        pstmt=conn.prepareStatement(sql);
        //设置参数
        pstmt.setString(1,username);
        pstmt.setString(2,password);
        //执行SQL语句,SQL已经预处理了,执行时不需要传入SQL
        rs = pstmt.executeQuery();
        //判断结果集中是否有数据(查询到了)
        if (rs.next()) {
            flag = true;
        } else
            flag = false;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.release(conn, pstmt, rs);
    }
    return flag;

}

@Test//注解
/**
 * 保存数据
 */
public void demo1()  {
    Connection conn=null;
    PreparedStatement pstmt=null;

    try {
        //获得连接
        conn= JDBCUtils.getConnection();
        //编写SQL语句
        String sql="insert into user values (null,?,?,?)";
        //预处理SQL
        pstmt= conn.prepareStatement(sql);
        //设置参数的值
        pstmt.setString(1,"111");//或直接setObject()
        pstmt.setString(2,"ddd");
        pstmt.setString(3,"李四");
        //执行SQL
        int i= pstmt.executeUpdate();
        if(i>0){
            System.out.println("保存成功!");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        JDBCUtils.release(conn,pstmt);

    }

}

数据库连接池(一块内存):很多用户通过服务器端的程序,调用数据访问对象,创建连接,跟数据库进行交互,用户每次请求都需要向数据库获得连接(用户访问请求->JDBC(从数据库连接池获得连接)->数据库)

在这里插入图片描述

访问时不需要再创建连接,而是从连接池中拿一个出来,用完以后再归还

在这里插入图片描述

C3P0连接池

package jdbcDemo3;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import utils.JDBCUtils;
import org.junit.Test;
import utils.JDBCUtils2;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * 连接池的测试类
 */
public class DataSourceDemo1 {
    @Test
    /**
     * 使用配置文件的方式,属性文件或xml文件(放在src路径下,默认就会查找)
     * 将创建连接池抽取成工具类
     *
     */
    public void demo2(){
        //获得连接
        Connection conn=null;
        PreparedStatement pstmt=null;
        ResultSet rs=null;
        try {

            conn=JDBCUtils2.getConnection();
            //编写SQL
            String sql="select * from user";
            //预编译SQL
            pstmt=conn.prepareStatement(sql);
            //设置参数
            //执行SQL
            rs= pstmt.executeQuery();
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                String name=rs.getString("name");
                System.out.println(uid+" "+username+" "+password+" "+name);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //连接池内部已经增强了Connection的close(),原有的销毁变成归还了,不用管归还的操作
            JDBCUtils2.release(conn,pstmt,rs);
        }
    }


    @Test
    /**
     * 手动设置连接池
     */
    public void demo1(){

        //获得连接
        Connection conn=null;
        PreparedStatement pstmt=null;
        ResultSet rs=null;
        try {
            //创建连接池
            ComboPooledDataSource dataSource=new ComboPooledDataSource();
            //设置连接池的相关参数
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbctest?useUnicode=true&characterEncoding=utf8");
            dataSource.setUser("root");
            dataSource.setPassword("1984");
            dataSource.setMaxPoolSize(20);
            dataSource.setInitialPoolSize(3);
            //从连接池中获得连接
            conn= dataSource.getConnection();
            //编写SQL
            String sql="select * from user";
            //预编译SQL
            pstmt=conn.prepareStatement(sql);
            //设置参数
            //执行SQL
            rs= pstmt.executeQuery();
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                String name=rs.getString("name");
                System.out.println(uid+" "+username+" "+password+" "+name);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
        //连接池内部已经增强了Connection的close(),原有的销毁变成归还了,不用管归还的操作
        JDBCUtils2.release(conn,pstmt,rs);
    }
    }
}

抽取工具类


/**
 * 抽取工具类
 */

public class JDBCUtils2 {
    private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();//,保证一个程序内,连接池只被初始化一次


    /**
     * 获得连接的方法
     */
    public static Connection getConnection() throws Exception {

        Connection conn = dataSource.getConnection();
        return conn;
    }
}

xml文件

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

  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
   <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbctest</property>
   <property name="user">root</property>
   <property name="password">1984</property>
   <property name="initialPoolSize">5</property>
   <property name="maxPoolSize">20</property>
  </default-config>
  
</c3p0-config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值