第二节JDBC

JDBC

1. jdbc概述

  1. 什么是 jdbc? 为什么要学习 jdbc

    • JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术
    • jdbc 是java和数据库的连接的 桥梁是所有持久层框架底层设计的核心。

2. 前期准备

  1. 创建数据库,在数据库中创建一个Account账目表,并插入三条记录,然后利用jdbc连接数据库并打印在控制台上。

  2. 开发步骤:

    • 准备数据库jdbc_db,并创建表Account,如下:
    -- 创建数据库 
    	create database jdbc_db charset utf8;
    
    -- 创建表数据 
    	create table account(
    		id  int  primary key auto_increment,
    		acc_name varchar(20),
    		money decimal (10.2)
    
    );
    --插入数据
    	insert into account values(null,"张三",1000);
    	insert into account values(null,"李四",1000);
    	insert into account values(null,"王五",1000);
    
  3. 创建 JAVA工程

    • 首先下载 java与数据库的 连接驱动,因为咱们使用的是mysql 8.0.30 版本,以前的5.7 版本就无法使用,学习者需要注意版本。
    • MySQL官网连接网址 然后下载,下载zip压缩即可。

在这里插入图片描述

  1. 将驱动程序,放到该工程中。
    • 新建目录 lib ,复制驱动到该目录中。

在这里插入图片描述

  1. 将驱动添加到项目环境中。
    • 选中驱动 右键 > add as library。确认即可。
      在这里插入图片描述

3. JAVA 访问数据库

3.1 Jdbc 快速入门案例

  1. 查询表,并将结果显示到控制台。

    • 需要六个步骤,如下图:
    • 数据库驱动,com.mysql.cj.jdbc.Driver
    • url jdbc:mysql://localhost:3306/数据库?characterEncoding=utf-8

在这里插入图片描述

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 *	java 连接数据库快速入门案例
 * @Author Old Wu
 */
public class Jdbc_Connection {
    public static void main(String[] args) throws Exception{
        //1.注册数据库驱动,com.mysql.cj.jdbc.Driver 是新版本,之前5.x com.mysql.jdbc.Driver,需要注意。
        Class.forName("com.mysql.cj.jdbc.Driver"); //为了测试直接抛 throws Exception
        //2.获取数据库连接
        /*
            url参数用来确定连接的数据库信息: 数据库机器ip 端口号port 数据库名db_name 连接的参数,比如编解码集
            url格式:jdbc:mysql://ip:port/db_name?k=v参数

            2.2 要使用 import java.sql.Connection;
         */
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_db?characterEncoding=utf-8",
                "root", "root");

        // 3.获取传输器
        Statement statement = con.createStatement();

        //4.发送sql到服务器,等待返回结果。
        String select = "select * from account"; // sql 查询语句
        ResultSet res = statement.executeQuery(select);//发送查询结果,返回结果集

        //5.处理结果
        //遍历结果集
        while (res.next()){  //判断结果集中是否有数据,有返回true,无则false。
            int id = res.getInt("id");
            String acc_name = res.getString("acc_name");
            BigDecimal money = res.getBigDecimal("money");
            System.out.println("输出结果:  "+id+" : "+acc_name+" : "+money);
        }

        // 6.释放资源
        // 6.1 原则,先获取的后释放,后获取的先释放
        res.close();
        statement.close();
        con.close();

        System.out.println("sql执行完成");
    }
}

3.2 jdbc入门中参数解释

  1. 注册驱动 Class.forName("com.mysql.cj.jdbc.Driver");

    • 这句语句并没有返回值,它是否有意义?
    • 相当于加载该类时,静态方法就注册了驱动。jdbc就加载mysql驱动,并管理驱动。
      在这里插入图片描述
  2. 获取数据库连接 Connection conn = DriverManager.getConnection(url,username,password);

    • url 连接 jdbc:mysql://localhost:3306/jdbc_db?characterEncoding=utf-8";
    • characterEncoding=utf-8 防止中文乱码,别写错(写错不会提示,就不生效)。

在这里插入图片描述

  1. 传输器 Statement statement = conn.createStatement();
    • 该方法相当于获取向数据库发送sql语句的传输对象,Statement,该对象上提供了发送sql方法。
	1.executeQuery(String sql) :用于向数据库发送查询类型的sql语句,返回是一个ResultSet对象中。
								-- 相当于返回的是一个表格,是一个结果集,需要使用ResultSet去处理。

	2.executeUpdate(String sql): 用于向数据库发送更新(增加,删除,修改)类型sql语句,返回一个int值,表示的是影响的是记录行数。
	
  1. 结果集对象 ResultSet

    • 用户封装查询语句,非常重要的一个对象。上面提供了获取数据的遍历方法。
    • next() 遍历数据行的方法,指向数据行索引,并移动下一行,返回结果true 则箭头指向行有数据,false则无。
    • 提供了获取列的方法如: getInt().... getString()等。
  2. 释放结果

    • 资源一定要按照顺序关闭,越晚获取的越早关闭。
    • 建议try{}catch(){}finall{...},以免造成上面异常资源没关出现。
 		res.close();
        statement.close();
        conn.close();


推荐使用  finall{

}

  			 if (statement!=null) { //如果不为空就关闭。
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }

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

4. Jdbc 的增删改查

4.1 新增

  1. account表中插入一条记录,姓名 “赵六”,money 为3500的记录;
/**
 * jdbc 相关操作,增删改查
 * @Author Old Wu
 */
public class Jdbc_Test {
    @Test
    public void insert_Test(){
        //还是6个步骤;并在最后需要处理异常
        // 7.在finall处理关闭资源
        Statement statement =null;
        Connection connection =null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.创建数据库连接
             connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_db?characterEncoding=utf-8",
                    "root", "root");
            //3.获取传输器
             statement = connection.createStatement();
            //4,发送sql等待返回结果,这里面使用单引号和双引号一样,但是双引号需要转义。
            String sql = "insert into account values(4,'赵六','3500')";
            int i = statement.executeUpdate(sql);
            //5,处理结果
            System.out.println("影响条数"+i);
            //System.out.println("验证");

            // statement.close(); //在finally去处理。
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6关闭资源,标准写法
                if (statement!=null) { //如果不为空就关闭。
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }

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

        }
    }

}

4.2 修改

  1. account表中,名为张三的记录中money修改为 2000;
    • 会发现每次都需要写重复代码,注册,连接,关资源等,如何处理? 将重复代码封装成工具类 JdbcUtils.class,以减少代码臃肿。
    • 代码片段,如下:
mian 方法同上 新增。

   //2.修改方法
    @Test
    public void update_Test(){
        // 将方法提取出,finally 无法找到变量
        Connection conn = null;
        Statement statement=null;
        try {
            //获取连接方法
            conn = JdbcUtils.getConn();
            statement = conn.createStatement();
            //发送sql给数据库,等待返回数据
            String sql ="update account set money=2000 where acc_name ='张三'";
            int i = statement.executeUpdate(sql);

            System.out.println("影响结果 "+i);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(conn,statement,null); // 没有就null
        }
    }
  • 封装的JdbcUtils.class,工具类。
/**
 * 该工具为jdbc 封装连接工具
 * @Author lpx
 */
public class JdbcUtils {

    private JdbcUtils(){} //私有构造方法
    /**
     * 连接数据库
     * @return
     */
    public static Connection getConn(){
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_db?characterEncoding=utf-8",
                    "root", "root");
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }


    /**
     * 关闭资源方法。
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void close(ResultSet resultSet,Statement statement,Connection connection){

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

        if (statement!=null) { //如果不为空就关闭。
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

4.3 查询

  1. account表中,查询姓名为 张三的记录。
    • 查询,需要ResultSet对象。
    • 代码片段,如下:
//3.查询方法
    @Test
    public void select_Test(){

        Connection conn=null;
        Statement statement=null;
        ResultSet resultSet = null;
        try {
             conn = JdbcUtils.getConn();
             statement = conn.createStatement();
             resultSet = statement.executeQuery("select * from account where acc_name ='张三'");
             //遍历方法查询结果
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String acc_name = resultSet.getString("acc_name");
                String money = resultSet.getString("money");

                System.out.println("查询结果 :"+ id +":"+acc_name+":"+money);

            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(conn,statement,resultSet);
        }
    }

4.4 删除

  1. account表中,id 为4的记录。
    • 代码片段,如下:
  //4.删除方法
    @Test
    public void  delete_Test(){
        Connection conn =null;
        Statement statement =null;
        try {
             conn = JdbcUtils.getConn();
             statement = conn.createStatement();

            int i = statement.executeUpdate("delete from account where id = 4");
            System.out.println("影响条数"+i);

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.close(conn,statement,null);
        }
    }

5. PreparedStatement

  1. 上面案例中使用的是传输器 Statement 传输对象,而在开发中我们用的更多的传输器对象是 PreparedStatement 传输对象,该对象是 Statement子接口,更安全,并且更能提高程序的执行效率。

5.1 模拟登录案例

  1. 通过模拟登录案例,引发出一个重要的安全内容,SQL 注入 问题。
    • 在之前准备创建表名user,在数据库 jdbc_db中,并插入数据。
    • 新建类名 LoginUser.class模拟登录环境与数据库对接数据。
-- 在数据库jdbc_db,中创建表user

create table user(
	id int primary key auto_increment,
	username varchar(20),
	password varchar(20)	
);

-- 插入相关数据
insert into user values(null,"张三","123");
insert into user values(null,"李四","1234"); 

/**
 * 注意提前创建表,和插入数据。
 * 模拟登录案例。
 */
public class LoginUser {
    public static void main(String[] args) {

        //1.提示用户输入用户名和密码
        System.out.println("请输入用户名:");
        String userName = new Scanner(System.in).next();
        System.out.println("请输入密码: ");
        String passWord = new Scanner(System.in).next();

        //2.拿到了用户名和密码之后需要和数据库中的用户名和密码进行比较
        login(userName,passWord);
    }

    /**
     * 通过jdbc连接数据库进行校验输入用户名和密码
     * @param userName
     * @param passWord
     */
    private static void login(String userName, String passWord) {
        //1.如何连接数据库?6个步骤。
        Connection conn =null;
        Statement statement =null;
        ResultSet resultSet =null;

        try {
             conn = JdbcUtils.getConn();
             statement = conn.createStatement();
             //2 需要注意实际上使用参数传递过来,进行拼串输入,用户名和密码 '"+userName+"'
             resultSet = statement.executeQuery("select * from user where username='"+userName+"' and passwor d= '"+passWord+"'");

             //处理返回的结果集,使用if就是看是否判断成功,即可。
            if (resultSet.next()){
                System.out.println("用户名与密码正确,登录成功");
            }else{
                System.out.println("用户名与密码错误,登录失败");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            JdbcUtils.close(resultSet,statement,conn);
        }
    }
}

输出结果:
在这里插入图片描述

5.2 安全问题: SQL 注入

  1. 什么叫SQL注入? 什么情况下会引发这样的问题!? 该怎样去解决!?
    • 使用PreparedStatementStatement 安全的方式就解决。
    • 注意以下,其中2种注入方式:

在这里插入图片描述
在这里插入图片描述

5.3 如何解决Sql注入问题

  1. sql注入在2010年的时候,那时候技术不完善,但是随着现在技术的发展,早就有如何解决这样的问题了。
    • 使用 正则表达式去校验,如输入框中输入的or # 或者其它 字符
    • 使用PreparedStatementStatement 安全的方式就解决。
    • 提示: 传递的参数需要使用 占位符去处理。
/**
 * 改造登录案例
 使用PreparedStatement 替换 Statement解决注入问题。
 */
public class LoginUser2 {
    public static void main(String[] args) {

        System.out.println("请输入用户名:");
        String userName = new Scanner(System.in).next();
        System.out.println("请输入密码:");
        String passWord = new Scanner(System.in).next();

        //登录方法,通过jadb与数据库进行连接判断
        login(userName,passWord);
    }

    /**
     * 处理用户输入用户名和密码,通过jdbc连接判断数据库中,是否正确。
     * @param userName
     * @param passWord
     */
    private static void login(String userName, String passWord) {

        // 为了finally里能找到变量
        Connection conn = null;
        PreparedStatement ps =null;
        ResultSet resultSet =null;

        try {
            conn = JdbcUtils.getConn();
            //使用preparedStatement 传递的参数需要使用占位符去处理 ?
            /*1.
                String  sql = "select * from user where username=? and password=?";
                ps = conn.prepareStatement(sql);
              相当于把 查询sql的骨架发送给数据库。
             */
            String  sql = "select * from user where username=? and password=?";
            ps = conn.prepareStatement(sql);
            //2.设置占位符的参数,可以设置相应的类型。
            ps.setString(1,userName);
            ps.setString(2,passWord);

            //3. 将拼接好的 sql发送到数据库。
             resultSet = ps.executeQuery();

             //4处理返回结果
            if (resultSet.next()){
                System.out.println("登录成功");
            }else{
                System.out.println("登录失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.close(resultSet,ps,conn);//ps使用多态进行处理。
        }
    }
}

在这里插入图片描述

6. 扩展: 常见错误

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴琼老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值