• Java学习--JDBC


    JDBC概念

    JDBC概念

    就是使用Java语言操作关系型数据库的一套API 全称:( Java DataBase Connectivity ) Java 数据库连接

    我们开发的同一套Java代码是无法操作不同的关系型数据库,因为每一个关系型数据库的底层实现细节都不一样。如果这样,问题就很大了,在公司中可以在开发阶段使用的是MySQL数据库,而上线时公司最终选用oracle数据库,我们就需要对代码进行大批量修改,这显然并不是我们想看到的。我们要做到的是同一套Java代码操作不同的关系型数据库,而此时sun公司就指定了一套标准接口(JDBC),JDBC中定义了所有操作关系型数据库的规则。众所周知接口是无法直接使用的,我们需要使用接口的实现类,而这套实现类(称之为:驱动)就由各自的数据库厂商给出。

    JDBC本质

    各个数据库厂商去实现这些套接口,提供数据库驱动jar包
    我们可以使用这些套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

    JDBC的好处

    各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
    可随时替换底层数据库,访问数据库的Java代码基本不变

    步骤及具体操作

    java操作数据库的流程

    1.编写java代码
    2.java代码将SQL发送到MySQL服务端
    3.MySQL服务端接收到SQL语句并执行该SQL语句
    4.将SQL语句执行的结果返回给java代码

    编写代码步骤

    创建工程,导入驱动jar包

    将mysql的驱动包放在模块下的lib目录(随意命名)下,并将该jar包添加为库文件

    在添加为库文件的时候,有三个选项

    Global Library : 全局有效

    Project Library : 项目有效

    Module Library : 模块有效

    这里可以选择模块有效

     

    接下来就是在src中创建类

    注册驱动

    Class.forName("com.mysql.jdbc.Driver");

    获得连接

    Connection conn = DriverManager.getConnection(url, username, password);
    java代码需要发送给MySQL服务端,就需要先建立连接

    定义SQL语句

    String sql =  “update…” ;

    获取执行SQL对象

    执行SQL语句需要SQL执行对象,而这个执行对象就是Statement对象
    Statement stmt = conn.createStatement();

    执行SQL

    stmt.executeUpdate(sql);  

    处理返回结果
    释放资源

    先开的后关,后开的先关

    1. import java.sql.Connection;
    2. import java.sql.DriverManager;
    3. import java.sql.Statement;
    4. public class JDBCDemo {
    5. public static void main(String[] args) throws Exception {
    6. //1.注册驱动
    7. // Class.forName("com.mysql.jdbc.Driver");
    8. //2.获取连接
    9. String url="jdbc:mysql://127.0.0.1:3306/bookmal?useSSL=false&useServerPrepStmts=true&serverTimezone=UTC";
    10. String username="root";
    11. String password="123456";
    12. Connection conn = DriverManager.getConnection(url, username, password);
    13. //3.定义sql语句
    14. String sql="UPDATE `user` SET `password`=222 WHERE id = 2";
    15. //4.获取执行sql的对象
    16. Statement stmt = conn.createStatement();
    17. //5.执行sql
    18. int count = stmt.executeUpdate(sql);//受影响的行数
    19. //6.处理的结果
    20. System.out.println(count);
    21. //7.释放资源
    22. stmt.close();
    23. conn.close();
    24. }
    25. }

    JDBC API

    DriverManager(驱动管理类)

    注册驱动

    registerDriver用于注册驱动,但是我们在写注册驱动的时候写的是Class.forName("com.mysql.jdbc.Driver");   这是因为该类中的静态代码块中已经执行了DriverManager对象的registerDriver()方法的注册,所以我们只需要加载Driver类,该静态代码块就会执行。而Class.forName("com.mysql.jdbc.Driver");就可以加载Driver类

    在MySql5之后的驱动包,可以省略注册驱动的步骤

    获取数据库连接

    getConnection(String url,String user,String password)

    url:

    jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…

    Mysql8.0以上版本的数据库连接有所不同

    com.mysql.jdbc.Driver需要改为com.mysql.cj.jdbc.Driver
    MySQL8.0以上版本不要SSL连接的,需要显示关闭
    allowPublicKeyRetrieval允许客户端从服务器获取公钥
    最后还需要设置时区
     

    user:用户名
    password:密码

    Connection

    获取执行SQL的对象

    普通执行SQL对象  Statement createStatement()
    预编译SQL的执行SQL对象:防止SQL注入  prepareStatement prepareStatement(sql)
    执行存储过程的对象   CallableStatement prepareCall(sql)

    管理事务

    开启事物:BEGIN或者START TRANSACTION
    提交事物:COMMIT
    回滚事物:ROLLBACK

    Statement

    Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。

    ResultSet

    执行了DQL语句就会返回该对象   ResultSet  executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

    boolean  next()
    将光标从当前位置向前移动一行
    判断当前行是否为有效行

    方法返回值说明:
    true  : 有效航,当前行有数据
    false : 无效行,当前行没有数据

    xxx  getXxx(参数):获取数据
    xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
    参数:
             int类型的参数:列的编号,从1开始
             String类型的参数: 列的名称

    PreparedStatement
        预编译SQL语句并执行:预防SQL注入问题
        SQL注入
            SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

    比如下面这个代码:

    1. import java.sql.*;
    2. import java.util.Scanner;
    3. public class JDBCDemo02 {
    4. public static void main(String[] args) throws SQLException {
    5. Scanner sc= new Scanner(System.in);
    6. System.out.println("请输入用户名:");
    7. String userName = sc.next();
    8. System.out.println("请输入密码:");
    9. String pwd = sc.next();
    10. //1.注册驱动
    11. // Class.forName("com.mysql.jdbc.Driver");
    12. //2.获取连接
    13. String url="jdbc:mysql://127.0.0.1:3306/bookmal";
    14. String username="root";
    15. String password="123456";
    16. Connection connection = DriverManager.getConnection(url, username, password);
    17. // 3、获取发送SQL对象
    18. Statement statement = connection.createStatement();
    19. // 4、执行SQL语句
    20. String sql = "select * from user where userName='" + userName
    21. + "' and password = '" + pwd + "'";
    22. ResultSet resultSet = statement.executeQuery(sql);
    23. // 5、处理结果:只要resultSet.next()结果为true,说明查询到了你的用户名和密码,否则,没有查询到你的用户名和密码,从而说明你的用户名或者密码错误
    24. if (resultSet.next()) {
    25. System.out.println("用户名和密码正确,登录成功");
    26. } else {
    27. System.out.println("用户名或密码错误,登录失败");
    28. }
    29. // 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关
    30. resultSet.close();
    31. statement.close();
    32. connection.close();
    33. sc.close();
    34. }
    35. }

     

    输入结果正确时是可以登陆的

    但是如果恶意的修改, 

    即使密码不正确也可以登录成功,因为这里面的字符串时拼接起来并且传到数据库中的,所以在数据库中就相当于是 select * from user where username = 'sjdljfld' and password = ''or '1' = '1'

    所以可以使用PreparedStatement替换Statement,它将特殊字符进行了转义。在每个 的前面都加上了/,这样的话安全性更高

    使用工具类简化代码

    使用DBUtil提高代码的重用性

    1. public class DBUtils {
    2. /**
    3. *重用性方案 获取连接,释放资源
    4. */
    5. static {
    6. try {
    7. Class.forName("com.mysql.cj.jdbc.Driver");
    8. } catch (ClassNotFoundException e) {
    9. e.printStackTrace();
    10. }
    11. }
    12. //1.获取连接
    13. public static Connection getConnection() {
    14. Connection connection = null;
    15. try {
    16. connection = DriverManager.getConnection(
    17. "jdbc:mysql://localhost:3306/bookmal", "root", "123456");
    18. } catch (SQLException e) {
    19. e.printStackTrace();
    20. }
    21. return connection;
    22. }
    23. public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
    24. try {
    25. if (resultSet != null) {
    26. resultSet.close();
    27. }
    28. if (statement != null) {
    29. statement.close();
    30. }
    31. if (connection != null) {
    32. connection.close();
    33. }
    34. } catch (SQLException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    1. import java.sql.Connection;
    2. import java.sql.PreparedStatement;
    3. import java.sql.ResultSet;
    4. import java.sql.SQLException;
    5. import java.util.Scanner;
    6. public class JDBCDemo01 {
    7. public static void main(String[] args) throws SQLException {
    8. Scanner sc = new Scanner(System.in);
    9. System.out.println("请输入用户名:");
    10. String userName = sc.nextLine();
    11. System.out.println("请输入密码:");
    12. String pwd = sc.nextLine();
    13. //2.获得连接
    14. Connection connection = DBUtils.getConnection();
    15. // 3、获取发送SQL对象
    16. String sql = "select * from user where userName = ? and password=?;";
    17. PreparedStatement preparedStatement = connection.prepareStatement(sql);
    18. // 4、绑定参数,有多少个?绑定多少个参数值
    19. preparedStatement.setString(1, userName);
    20. preparedStatement.setString(2, pwd);
    21. // 5、执行SQL语句,并处理结果
    22. ResultSet resultSet = preparedStatement.executeQuery();
    23. if (resultSet.next()) {
    24. System.out.println("用户名和密码正确,登录成功");
    25. } else {
    26. System.out.println("用户名或密码错误,登录失败");
    27. }
    28. // 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关
    29. DBUtils.closeAll(connection, preparedStatement, resultSet);
    30. sc.close();
    31. }
    32. }

    数据库连接池

    数据库连接池简介
        数据库连接池是个容器,负责分配、管理数据库连接(Connection)
        它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
        释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
        好处
            资源重用
            提升系统响应速度
            避免数据库连接遗漏

    常见的数据库连接池有 DBCP、C3P0、Druid。

    • Druid连接池是阿里巴巴开源的数据库连接池项目

    • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

    Druid的使用

    • 导入jar包 druid-1.1.12.jar

    • 定义配置文件

    • 加载配置文件

    • 获取数据库连接池对象

    • 获取连接

    • 在获取了连接之后就可以为所欲为了

    配置文件的编写

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/bookmal?useSSL=false&serverTimeZone=UTC
    username=root
    password=123456
    #初始化连接数量
    initialSize=5
    #最大连接数
    maxActive=10
    #最大等待时间
    maxWait-3000
    
    1. public class DruidDemo {
    2. public static void main(String[] args) throws Exception {
    3. //1.导入jar包
    4. //2.定义配置文件
    5. //3. 加载配置文件
    6. Properties prop = new Properties();
    7. prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    8. //4. 获取连接池对象
    9. DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    10. //5. 获取数据库连接 Connection
    11. Connection connection = dataSource.getConnection();
    12. System.out.println(connection); //获取到了连接后就可以继续做其他操作了
    13. //System.out.println(System.getProperty("user.dir"));
    14. }
    15. }

  • 相关阅读:
    Java练习题2022-1
    『现学现忘』Docker基础 — 34、DockerFile文件详解
    【POJ No. 3067】 公路交叉数 Japan
    【迁移ORACLE数据到MogDB/openGauss时的字符集问题】
    安装Linux虚拟机——以ubuntukylin-16.04.7-desktop-amd64.iso为例
    如何实现一个SQL解析器
    c++ 之安装opencv显示图片
    Halcon image_points_to_world_plane和image_to_world_plane分析
    React面试题:React.Component和React.PureComponent的区别?
    Vue组件之间的通信-父传子-子传父
  • 原文地址:https://blog.csdn.net/qihaojinqiuma/article/details/127388170