首页 > 其他分享 >JDBC相关

JDBC相关

时间:2024-05-06 11:34:53浏览次数:27  
标签:JDBC String 数据库 connection SQL close 相关 password

  1. 什么是JDBC,为什么要使用JDBC?

    在web开发中,不可避免的地要使用数据库来存储和管理数据。为了在java语言中提供数据库访问的支持,Sun公司于1996年提供了一套访问数据的标准Java类库,即JDBC。
    JDBC,全称是Java Database Connectivity,它是一套统一的、基于Java语言的关系数据库编程接口规范,
    该规范允许你把SQL语句作为参数通过JDBC接口发送给远端数据库,远端数据库接受到你的SQL后进行语法分析、验证,然后执行、响应。

    应用程序使用JDBC访问特定的数据库时,需要与不同的数据库驱动进行连接。
    由于不同数据库厂商提供的数据库驱动不同,因此,为了使应用程序与数据库真正建立连接,JDBC不仅需要提供访问数据库的API,还需要封装与各种数据库服务器通信的细节为了帮助大家更好地理解应用程序如何通过JDBC访问数据库。

  2. 第一个JDBC程序

    package com.example.test01;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.util.Date;
    public class Demo {
        public static void main(String[] args) throws Exception {
            //1.注册数据库的驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.通过DriverManager获取数据库连接
            String url="jdbc:mysql://localhost:3306/test";
            String username="root";
            String password="123456";
            Connection connection=DriverManager.getConnection(url, username, password);
            //通过connection对象获取statement对象
            Statement statement=connection.createStatement();
            //使用statement对象执行SQL语句
            String sql ="select * from users";
            ResultSet resultSet=stmt.executeQuery(sql);
            //操作ResultSet结果集
            System.out.println("id|name|password|email|birthday");
            while(rs.next()){
                //通过列名获取指定的字段
                int id=resultSet.getInt("id");
                String name=resultSet.getString("name");
                String password=resultSet.getString("password");
                String email=resultSet.getString("email");
                Date birthday=resultSet.getDate("birthday");
                System.out.println(id+"|"+name+"|"+password+"|"+email+"|"+"|"+birthday);
            }
            //回收数据库资源
            resultSet.close();
            statement.close();
            connection.close();   
        }
    }
    /*
    步骤总结:
    1)加载并注册数据库驱动
    2)通过DriverManager获取数据库连接
    3)通过Connection对象获取Statement对象
    4)使用Statement执行SQL语句
    5)操作ResultSet结果集
    */
    
  3. 每一个对象的解释

    //固定写法,加载驱动
    Class.forName("com.mysql.cj.jdbc.Driver"); 
    //connection 代表数据库,mysql8之后再写url的时候注意要增加的参数
    String url="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=true&serverTimezone=GMT%2B8";
    Connection connection = DriverManager.getConnection(url, username, password);
    //数据库设置自动提交
    //事务提交
    //事务回滚
    connection.setAutoCommit();
    connection.commit();
    connection.rollback();
    //编写SQL
    String sql = "select * from student";
    //查询操作,返回ResultSet
    statement.executeQuery();
    //执行任何的SQL
    statement.execute();
    //更新、插入、删除 都是用这个,返回的是一个受影响的行数   
    statement.executeUpdate();
    //获取指定的数据类型
    resultSet.getObject();
    //在不知道列的类型的情况下使用
    resultSet.getInt();
    resultSet.getString();
    //释放连接
    resultSet.close();
    statement.close();
    //耗资源 ,用完关闭
    connection.close();
    
  4. jdbc代码的封装

    若每次对数据库操作如果都像上面的案例一样,每操作一次都进行一次数据库的连接,驱动加载,资源关闭会显得非常麻烦,因此,封装一个工具类,帮助我们更方便快捷的进行这些资源的管理。

    //新建一个jdbc.properties文件,将连接参数都写入进去 
    driverClass=com.mysql.jdbc.Driver
    jdbcUrl=jdbc:mysql://localhost:3306/gp_01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
    username=root
    password=123456
    
    //资源管理工具类
    package com.jdbc.utils;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Arrays;
    import java.util.Properties;
    
    public class JdbcUtils {
    
        private static String jdbcUrl;
        private static String username;
        private static String password;
    
        static {
            //1.找到资源目录下的配置文件
            InputStream input = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
    
            //2.实例化 Properties 对象
            Properties properties = new Properties();
    
            try {
                //加载配置文件,完成配置文件的解析
                properties.load(input);
    
                //获取参数
                jdbcUrl = properties.getProperty("jdbcUrl");
                username = properties.getProperty("username");
                password = properties.getProperty("password");
    
                //加载驱动
                Class.forName(properties.getProperty("driverClass"));
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (input != null) {
                        input.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 获取连接对象
         *
         * @return java.sql.Connection 数据库连接对象
         */
        public static Connection getConnection() {
            Connection connection = null;
            try {
                connection = DriverManager.getConnection(jdbcUrl, username, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
    
        /**
         * 关闭资源方法,无结果集的情况
         *
         * @param connection 数据库连接对象资源
         * @param statement  数据库 SQL 语句搬运工资源
         */
        public static void close(Connection connection, Statement statement) {
            close(statement, connection);
        }
    
        /**
         * 关闭资源方法
         *
         * @param connection 数据库连接对象资源
         * @param statement  数据库 SQL 语句搬运工资源
         * @param resultSet  数据库查询结果集对象
         */
        public static void close(Connection connection, Statement statement, ResultSet resultSet) {
            close(resultSet, statement, connection);
        }
    
        /**
         * 内部私有化方法,统一处理数据库相关资源
         *
         * @param resources 不定长参数,统一关闭对应资源
         */
        private static void close(AutoCloseable... resources) {
            if (resources != null && resources.length > 0) {
                Arrays.stream(resources).forEach(source -> {
                    try {
                        if (source != null) {
                            source.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        }
    }
    /*
    在static静态代码块中,静态代码块随着类的加载而加载,而且只加载一次。通过加载配置文件,获得了必要的数据库参数,同时加载了驱动。
    
    获取数据库连接对象,通过DriverManager.getConnection(jdbcUrl, username, password)获得connection对象。
    
    关闭连接资源对象,这里使用了AutoCloseable 不定长参数来传入资源对象进行关闭,重载了两个close方法,分别对应了两种情况:
    
    * 第一种:关闭connection,statement对象(增删查操作)
    
    * 第二种:关闭 connection,statement,resultSet对象(查询操作)
    
    */
    
    
  5. SQL注入问题

    比如你待拼接的sql语句如下:
    String sql = "select * from user where name = '" + username
                    + "' and password = '" + password + "'";
    --正常情况下你回输入正常的用户名和密码,之后传给sql语句进行拼接:
    select * from user where name = 'root' and password = '123456';
    --会查到正常的你自己的信息;
    --但是当你输入不合法的字符串,导致sql语句进行拼接,例如你输入用户名为 "xxx"  密码为 "XXX' or '1' = '1" 时:
    select * from user where name = 'xxx' and password = 'XXX' or '1' = '1';
    --由于 '1' = '1' 恒成立, MySQL 将这个表的所有信息都查找出来了, 显然这是不合理的.
    
  6. 防止sql注入(PreparedStatement与Statement的区别)

    • 使用 PreparedStatement 时,不需要拼接 SQL 语句,因此可以避免因字符串拼接而产生的 SQL 注入问题。
    • Prepared Statement 可以对参数进行转义,从而避免输入的参数导致的 SQL 异常。
    • Prepared Statement 可以预编译 SQL 语句,并将编译后的语句保存到数据库服务器的缓存中,因此在执行多次相同的 SQL 语句时,可以大幅提高性能。
    //举个例子:
    //编写sql语句
    String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; 
    //根据连接字符串连接数据库
    Connection conn = DriverManager.getConnection(url, username, password); 
    //创建PreparedStatement 对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //传入参数
    pstmt.setString(1, "root"); 
    pstmt.setString(2, "123456"); 
    //执行方式
    ResultSet rs = pstmt.executeQuery(); 
    while (rs.next()) {     
     String username = rs.getString("username");    
     String password = rs.getString("password"); } 
    //释放资源
    rs.close();
    pstmt.close();
    conn.close();
    
    /*总结
    PreparedStatement通过以下方式防止SQL注入:
    1. 参数化查询
    PreparedStatement使用参数化查询,将用户输入的值作为参数传递给SQL语句,而不是将它们直接插入到SQL语句中。这样做可以防止攻击者通过恶意注入SQL语句来改变查询的语义。
    
    2. 自动处理转义字符
    PreparedStatement会自动处理必要的转义字符,确保特殊字符不会破坏SQL语句的结构。例如,单引号 ' 、反斜杠 \\ 等特殊字符在传递给PreparedStatement时会自动进行转义处理。
    
    3. 数据类型匹配
    PreparedStatement会对传递给它的参数进行数据类型匹配和格式验证。这样可以避免将字符串值错误地解析为数值、日期等类型,从而确保查询的准确性和安全性。
    
    4. 编译和重用
    PreparedStatement会对SQL语句进行预编译,并缓存编译后的查询计划。这样可以提高性能,并减少对数据库的负载。由于预编译的查询计划是在应用程序启动时创建的,而不是每次查询执行时都进行编译,这样也有助于防止攻击者在SQL注入中插入恶意代码。    
    */
    
    
  7. JDBC中给的事务操作

    public void testJDBCTransaction() {
    Connection conn = null;
    try {
    	// 1.获取数据库连接
    	conn = JDBCUtils.getConnection();
    	// 2.开启事务
    	conn.setAutoCommit(false);
    	// 3.进行数据库操作
    	String sql1 = "update user_table set balance = balance - 100 where user = ?";
    	update(conn, sql1, "AA");
    
    	// 模拟网络异常
    	//System.out.println(10 / 0);
    
    	String sql2 = "update user_table set balance = balance + 100 where user = ?";
    	update(conn, sql2, "BB");
    	// 4.若没有异常,则提交事务
    	conn.commit();
        } catch (Exception e) {
    		e.printStackTrace();
    		// 5.若有异常,则回滚事务
    		try {
    			conn.rollback();
    		} catch (SQLException e1) {
    			e1.printStackTrace();
    		}
        } finally {
            try {
    		//6.恢复每次DML操作的自动提交功能
    			conn.setAutoCommit(true);
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
            //7.关闭连接
    		JDBCUtils.closeResource(conn, null, null); 
        }  
    }
    
    
  8. 数据库连接池

    数据库连接池是一种维护数据库连接的技术,它允许应用程序在需要时从池中获取数据库连接,并在不需要连接时将其释放回池中。
    这种技术的主要目的是减少每次访问数据库时都要创建和销毁连接的开销,从而提高性能和资源利用率。

    主流连接池各项功能对比如下:
    参考:https://blog.csdn.net/jarniyy/article/details/121014633

标签:JDBC,String,数据库,connection,SQL,close,相关,password
From: https://www.cnblogs.com/hytip/p/18174671

相关文章

  • 异构数据源同步之表结构同步 → 通过 jdbc 实现,没那么简单
    开心一刻今天坐沙发上看电视,旁边的老婆拿着手机贴了过来老婆:老公,这次出门旅游,机票我准备买了哈我:嗯老婆:你、我、你爸妈、我爸妈,一共六张票老婆:这上面还有意外保险,要不要买?我:都特么团灭了,还买啥保险?异构数据源同步概念介绍数据源,不只是包含关系型数据库,还包括NoSQL、数......
  • 深度学习相关理论
    一、深度学习相关理论1.神经网络概述     2.卷积神经网络CNN ①卷积层——计算方法是大矩阵内部×小矩阵=较小矩阵,作用是特征提取  ②池化层——计算方法是大矩阵通过选取最大值或是平均值变成小矩阵,作用是降维、提高计算效率    3.激活函......
  • BGP 相关术语
    BGP相关术语协议相关BGP:边界网关协议(BorderGatewayProtocol,BGP)是一种用来在路由选择域之间交换网络层可达性信息(NetworkLayerReachabilityInformation,NLRI)的路由选择协议;NLRI:NetworkLayerReachabilityInformation,网络层可达性信息;由于BGP传递的信息已经不限于路......
  • 博客园数据备份相关
    OpenAPI文档文档地址,使用前必须先申请权限,应用介绍要详细点。这种方式支持随笔和文章,不支持笔记。管理后台备份只能在工作日18:00之后、8点之前或周六、周日进行操作,每天只允许备份一次。这种方式仅支持随笔。使用爬虫使用接口来模拟网页版的操作,使用Jsoup库来解析HTML内......
  • 二叉树相关的三个常见算法题
    算法题一//计算一颗二叉树的所有节点的数量intBinaryTree_CountNode(Tnode_t*root){intn1,n2;if(NULL==root){return0;}n1=BinaryTree_CountNode(root->lchild);n2=BinaryTree_CountNode(root->rchild);returnn1+......
  • 08_自相关
    第8章自相关8.1自相关的后果除了异方差,违反球形扰动项的另一情形是扰动项存在自相关。定义自相关(autocorrelation)/序列相关(serialcorrelation)对于\(\{\epsilon_1,\cdots,\epsilon_n\}\),如果存在\(i\nej\),使得\(E(\epsilon_i\epsilon_j|X)\ne0\),即协方差矩阵\(Var......
  • 【软件构造课程相关】幻方及其构造(上)
    介绍​幻方(MagicSquare),有时又称魔术方阵或纵横图,由一组排放在正方形中的整数组成,其每行、每列以及每一条主对角线的和均相等。通常幻方由从1到$N2$的连续整数组成,其中N为正方形的行或列的数目。因此N阶幻方有N行N列,并且所填充的数为从1到$N2$。​幻方可以使用N......
  • Noise label相关文章随记
    ContrastiveLearningImprovesModelRobustnessUnderLabelNoise2021观察:监督的鲁棒学习方法在有噪音的时候下降明显半监督的鲁棒学习能利用无标签的数据取得更好的效果那么监督的鲁棒学习方法的性能下降是由标签噪音引起的,还是不够好的表征引起的?作者的答案是学到的表......
  • c语言实现vector及其相关函数(自存)
    #include<stdio.h>#include<stdlib.h>#definePREALLOC_MAX1024#defineDEFAULT_CAPACITY8typedefintE;typedefstruct{E*elements;//指向堆空间的数组intsize;//元素的个数intcapacity;//数组的容量}Vector;voidpush_back(Vect......
  • cpp字符串相关
    字符串相关文章参考:[详解-字符串]C++必知必会字符串-string常用各种操作解析-知乎(zhihu.com)C++字符串(string)常用操作总结-知乎(zhihu.com)c++读取字符串和字符的6种函数_c++获取字符串的每个字符-CSDN博客头文件#include<string>定义字符串stringstr;初始......