• JDBC学习


    简介

    1.概念

    • JDBC就是使用Java语言操作关系数据库的一套API
    • 全程:Java DataBase Connectivity Java数据库连接

    2.本质

    • 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
    • 各个数据库厂商去实现这套接口,提供数据库驱动jar包
    • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

    3.好处

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

    4.步骤

    1.引入jar包

    • 新建lib
    • 将mysql的jar包复制到lib
    • 右键,选Add as Library
    • 模块生效

    2.实例

    1. public static void main(String[] args) throws ClassNotFoundException, SQLException {
    2. //1.注册驱动
    3. Class.forName("com.mysql.cj.jdbc.Driver");
    4. //2.获取连接
    5. String url="jdbc:mysql://127.0.0.1:3306/test";
    6. String userName="";
    7. String password="";
    8. Connection conn = DriverManager.getConnection(url, userName, password);
    9. //3.定义SQL
    10. String sql = "update account set money = 2000 where id = 1";
    11. //4.获取执行sql的对象Statement
    12. Statement stmt = conn.createStatement();
    13. //5.执行sql
    14. int count = stmt.executeUpdate(sql);//受影响的行数
    15. //6.处理结果
    16. System.out.println(count);
    17. //7.释放资源
    18. stmt.close();
    19. conn.close();
    20. }

    JDBC API 详解

    DriverManager

    1.注册驱动

    Class.forName("com.mysql.cj.jdbc.Driver");
    • 查看源码
    1. static {
    2. try {
    3. DriverManager.registerDriver(new Driver());
    4. } catch (SQLException var1) {
    5. throw new RuntimeException("Can't register driver!");
    6. }
    7. }
    • 提示
      • MySQL 之后的驱动包,可以省略注册驱动的步骤
      • 自动加载jar包中的META-INF/services/Java.sql.Driver文件中的驱动类

    2.获取连接

    static Connection	getConnection(String url, String user, String password)
    • 参数
    1. url:连接路径
    2. 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2..
    3. user:用户名
    4. password:密码

    Connection

    Connection(数据库连接对象)作用

    1. 获取执行SQL的对象
    • 普通执行SQL对象
    Statement createStatement()
    • 预编译SQL的执行SQL对象:防止SQL注入
    PreparedStatement	prepareStatement(String sql)
    • 执行存储过程的对象
     CallableStatement	prepareCall(String sql)
    • MySQL事务管理

    • JDBC事务管理:Connection 接口中定义了3个对应的方法

    Statement

    statement 作用

    • 执行SQL语句
    1. //执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。
    2. //执行DML,DDL语句
    3. //返回值:(1)DML语句影响的行数(2)DDL语句执行后,执行成功也可能返回0
    4. int executeUpdate(String sql)
    1. //执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。
    2. //返回值:ResultSet结果集对象
    3. ResultSet executeQuery(String sql)
      • 代码
    1. /**
    2. * 执行DML语句
    3. * @throws ClassNotFoundException
    4. * @throws SQLException
    5. */
    6. @Test
    7. public void testDML() throws ClassNotFoundException, SQLException {
    8. //1.注册驱动
    9. Class.forName("com.mysql.cj.jdbc.Driver");
    10. //2.获取连接
    11. String url="jdbc:mysql://127.0.0.1:3306/test";
    12. String userName="";
    13. String password="";
    14. Connection conn = DriverManager.getConnection(url, userName, password);
    15. //3.定义SQL
    16. String sql = "update account set money = 2000 where id = 1";
    17. //4.获取执行sql的对象Statement
    18. Statement stmt = conn.createStatement();
    19. //5.执行sql
    20. int count = stmt.executeUpdate(sql);//受影响的行数
    21. //6.处理结果
    22. //System.out.println(count);
    23. if(count>0){
    24. System.out.println("修改成功");
    25. }else{
    26. System.out.println("修改失败");
    27. }
    28. //7.释放资源
    29. stmt.close();
    30. conn.close();
    31. }
    1. /**
    2. * 执行DDL语句
    3. * @throws ClassNotFoundException
    4. * @throws SQLException
    5. */
    6. @Test
    7. public void testDDL() throws ClassNotFoundException, SQLException {
    8. //1.注册驱动
    9. Class.forName("com.mysql.cj.jdbc.Driver");
    10. //2.获取连接
    11. String url="jdbc:mysql://127.0.0.1:3306/test";
    12. String userName="";
    13. String password="";
    14. Connection conn = DriverManager.getConnection(url, userName, password);
    15. //3.定义SQL
    16. String sql = "drop database db1";
    17. //4.获取执行sql的对象Statement
    18. Statement stmt = conn.createStatement();
    19. //5.执行sql
    20. int count = stmt.executeUpdate(sql);//执行完DDL语句,可能是0
    21. //6.处理结果
    22. //System.out.println(count);
    23. // if(count>0){
    24. // System.out.println("修改成功");
    25. // }else{
    26. // System.out.println("修改失败");
    27. // }
    28. System.out.println(count);
    29. //7.释放资源
    30. stmt.close();
    31. conn.close();
    32. }

    ResultSet

    1.ResultSet(结果集对象)作用:

    • 封装了DQL查询语句的结果
    1. ResultSet stmt.executeQuery(sql)
    2. //执行DQL语句,返回ResultSet对象
    • 获取查询结果
    1. //(1)将光标从当前位置向前移一行。(2)判断当前行是否为有效行
    2. /*
    3. 返回值:
    4. true:有效行,当前行有数据
    5. false:无效行,当前行没有数据
    6. */
    7. boolean next()
    1. xxx getXxx(参数):获取数据
    2. /*
    3. xxx:数据类型,如:int getInt(参数);String getString(参数)
    4. 参数:
    5. int:列的编号,从1开始
    6. String:列的名称
    7. */

    2.使用步骤

      1. 游标向下移动一行,并判断改行是否有数据:next()
      2. 获取数据:getXxx(参数)
    1. //循环判断游标是否是最后一行
    2. While(rs.next()){
    3. //获取数据
    4. rs.getXxx(参数);
    5. }
      1. 代码示例
    1. /**
    2. * 执行DQl语句
    3. * @throws ClassNotFoundException
    4. * @throws SQLException
    5. */
    6. @Test
    7. public void testResultSet() throws ClassNotFoundException, SQLException {
    8. //1.注册驱动
    9. Class.forName("com.mysql.cj.jdbc.Driver");
    10. //2.获取连接
    11. String url="jdbc:mysql://127.0.0.1:3306/test";
    12. String userName="";
    13. String password="";
    14. Connection conn = DriverManager.getConnection(url, userName, password);
    15. //3.定义SQL
    16. String sql = "select * from account";
    17. //4.获取statement对象
    18. Statement stmt = conn.createStatement();
    19. //5.执行sql
    20. ResultSet rs = stmt.executeQuery(sql);
    21. // //6.处理结果
    22. // //光标向下移动一行,并且判断当前行是否有数据
    23. // while(rs.next()){
    24. // //获取数据 getXcc()
    25. // int id = rs.getInt(1);
    26. // String name = rs.getString(2);
    27. // double money = rs.getDouble(3);
    28. //
    29. // System.out.println(id);
    30. // System.out.println(name);
    31. // System.out.println(money);
    32. //
    33. // System.out.println("---------------");
    34. // }
    35. //6.处理结果
    36. //光标向下移动一行,并且判断当前行是否有数据
    37. while(rs.next()){
    38. //获取数据 getXcc()
    39. int id = rs.getInt("id");
    40. String name = rs.getString("name");
    41. double money = rs.getDouble("money");
    42. System.out.println(id);
    43. System.out.println(name);
    44. System.out.println(money);
    45. System.out.println("---------------");
    46. }
    47. //7.释放资源
    48. rs.close();
    49. stmt.close();
    50. conn.close();
    51. }

    3.案例

    • 需求:查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
    1. /**
    2. * 查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
    3. * 1.定义实体类Account
    4. * 2.查询数据,封装到Account对象中
    5. * 3.将Account对象存入ArrayList集合中
    6. *
    7. * @throws ClassNotFoundException
    8. * @throws SQLException
    9. */
    10. @Test
    11. public void testResultSet2() throws ClassNotFoundException, SQLException {
    12. //1.注册驱动
    13. Class.forName("com.mysql.cj.jdbc.Driver");
    14. //2.获取连接
    15. String url="jdbc:mysql://127.0.0.1:3306/test";
    16. String userName="";
    17. String password="";
    18. Connection conn = DriverManager.getConnection(url, userName, password);
    19. //3.定义SQL
    20. String sql = "select * from account";
    21. //4.获取statement对象
    22. Statement stmt = conn.createStatement();
    23. //5.执行sql
    24. ResultSet rs = stmt.executeQuery(sql);
    25. //创建集合
    26. ArrayList list = new ArrayList<>();
    27. //6.处理结果
    28. //光标向下移动一行,并且判断当前行是否有数据
    29. while(rs.next()){
    30. Account account = new Account();
    31. //获取数据 getXcc()
    32. int id = rs.getInt("id");
    33. String name = rs.getString("name");
    34. double money = rs.getDouble("money");
    35. System.out.println(id);
    36. System.out.println(name);
    37. System.out.println(money);
    38. //赋值
    39. list.add(account);
    40. }
    41. System.out.println(list);
    42. //7.释放资源
    43. rs.close();
    44. stmt.close();
    45. conn.close();
    46. }

    PreparedStatement

    1.作用

    • 预编译SQL语句并执行,预防SQL注入问题
    • SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法
    • 代码示例
    1. /**
    2. * 演示SQL注入
    3. *
    4. * @throws ClassNotFoundException
    5. * @throws SQLException
    6. */
    7. @Test
    8. public void testLogin_Inject() throws ClassNotFoundException, SQLException {
    9. //1.注册驱动
    10. Class.forName("com.mysql.cj.jdbc.Driver");
    11. //2.获取连接
    12. String url = "jdbc:mysql://127.0.0.1:3306/test";
    13. String userName = "";
    14. String password = "";
    15. Connection conn = DriverManager.getConnection(url, userName, password);
    16. //接受用户输入的用户名和密码
    17. String name = "fghfgh";
    18. String pwd = "' or '1' = '1";
    19. //定义SQL
    20. String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
    21. System.out.println(sql);
    22. //获取statement对象
    23. Statement stmt = conn.createStatement();
    24. //执行sql
    25. ResultSet rs = stmt.executeQuery(sql);
    26. //判断登录是否成功
    27. if(rs.next()){
    28. System.out.println("登录成功");
    29. }else {
    30. System.out.println("登录失败");
    31. }
    32. //释放资源
    33. rs.close();
    34. stmt.close();
    35. conn.close();
    36. }

    2.案例

    • 需求:完成用户登录
    select * from tb_user where username='zhangsan' and password='123' ;
    • 代码示例
    1. /**
    2. * 用户登录
    3. *
    4. * @throws ClassNotFoundException
    5. * @throws SQLException
    6. */
    7. @Test
    8. public void testLogin() throws ClassNotFoundException, SQLException {
    9. //1.注册驱动
    10. Class.forName("com.mysql.cj.jdbc.Driver");
    11. //2.获取连接
    12. String url = "jdbc:mysql://127.0.0.1:3306/test";
    13. String userName = "";
    14. String password = "";
    15. Connection conn = DriverManager.getConnection(url, userName, password);
    16. //接受用户输入的用户名和密码
    17. String name = "zhangsan";
    18. String pwd = "123";
    19. //定义SQL
    20. String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
    21. //获取statement对象
    22. Statement stmt = conn.createStatement();
    23. //执行sql
    24. ResultSet rs = stmt.executeQuery(sql);
    25. //判断登录是否成功
    26. if(rs.next()){
    27. System.out.println("登录成功");
    28. }else {
    29. System.out.println("登录失败");
    30. }
    31. //释放资源
    32. rs.close();
    33. stmt.close();
    34. conn.close();
    35. }

    3.步骤

    • 获取PreparedStatement对象
    1. //SQL语句中的参数值,使用?占位符替代
    2. String sql = "select * from tb_user where username = ? and password = ?";
    3. //通过Connection对象获取,并传入对应的sql语句
    4. PrepareStatement pstmt = conn.prepareStatement(sql);
    • 设置参数值
    PrepareStatement对象:setXxx(参数1,参数2) 给?赋值
    Xxx:数据类型;如setInt(参数1,参数2)
    参数:
        参数1:?的位置编号,从1开始
        参数2:?的值
    • 执行SQL
    1. executeUpdate();/executeQuery();
    2. 不需要传递参数
    • 代码
    1. @Test
    2. public void testLogin() throws ClassNotFoundException, SQLException {
    3. //1.注册驱动
    4. Class.forName("com.mysql.cj.jdbc.Driver");
    5. //2.获取连接
    6. String url = "jdbc:mysql://127.0.0.1:3306/test";
    7. String userName = "";
    8. String password = "";
    9. Connection conn = DriverManager.getConnection(url, userName, password);
    10. //接受用户输入的用户名和密码
    11. String name = "zhangsan";
    12. String pwd = "123";
    13. //定义SQL
    14. String sql = "select * from tb_user where username = ? and password = ?";
    15. //获取statement对象
    16. PreparedStatement pstmt = conn.prepareStatement(sql);
    17. //设置?的值
    18. pstmt.setString(1,name);
    19. pstmt.setString(2,pwd);
    20. //执行sql
    21. ResultSet rs = pstmt.executeQuery();
    22. //判断登录是否成功
    23. if(rs.next()){
    24. System.out.println("登录成功");
    25. }else {
    26. System.out.println("登录失败");
    27. }
    28. //释放资源
    29. rs.close();
    30. pstmt.close();
    31. conn.close();
    32. }

    4.原理

    • 好处
      1. 预编译SQL,性能更高
      2. 防止SQL注入:将敏感字符进行转义
    • 步骤
      1. PreparedStatement 预编译功能开启:useServerPreStmts=true
      2. 配置MySQl执行日志(重启mysql服务生效)

    • 原理
      1. 在获取Preparetatement对象时,将sql语句发送给mysql服务器进行检查,编译
      2. 执行时就不用在进行这些步骤速度更快
      3. 如果sql模板一样,则只需要进行一次检查,编译

    数据库连接池

    1.概念

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

    2.实现

    • 标准接口:DataSource
      • 官方提供的数据库连接池便准接口,由第三方组织实现此接口
      • 功能:获取连接
    Connection getConnection()
    • 常见的数据库连接池
      • DBCP
      • C3P0
      • Druid
    • Druid(德鲁伊)
      • Druid连接池是阿里巴巴开源的数据库连接池项目
      • 功能强大,性能优秀,是java语言最好的数据库连接池之一

    3.Druid 使用步骤

    1. 导入jar包druid
    2. 定义配置文件
    3. 加载配置文件
    4. 获取数据库连接池对象
    5. 获取连接
    6. 代码
    1. public static void main(String[] args) throws Exception {
    2. //1. 导入jar包druid
    3. //2. 定义配置文件
    4. //3. 加载配置文件
    5. Properties prop = new Properties();
    6. prop.load(new FileInputStream("src/main/java/com/example/javaWeb/druid.properties"));
    7. //4. 获取数据库连接池对象
    8. DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    9. //5. 获取连接
    10. Connection connection = dataSource.getConnection();
    11. System.out.println(connection);
    12. // System.out.println(System.getProperty("user.dir"));
    13. }

    练习

    1.增删改查

      • 查询所有数据
        1. 获取Connection
        2. 定义SQL:select* from tb_brand;
        3. 获取PreparedStatement对象
        4. 设置参数:不需要
        5. 执行SQL
        6. 处理结果:List
        7. 释放资源
      • 代码示例
    1. /**
    2. * 查询所有
    3. */
    4. @Test
    5. public void testSelectAll() throws Exception {
    6. Properties prop = new Properties();
    7. prop.load(new FileInputStream("src/main/java/com/example/javaWeb/druid.properties"));
    8. //4. 获取数据库连接池对象
    9. DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    10. //5. 获取连接
    11. Connection conn = dataSource.getConnection();
    12. //定义SQL
    13. String sql = "select* from tb_brand;";
    14. //获取pstmt对象
    15. PreparedStatement pstmt = conn.prepareStatement(sql);
    16. //执行sql
    17. ResultSet rs = pstmt.executeQuery();
    18. //处理结果
    19. Brand brand = null;
    20. ArrayList brands = new ArrayList<>();
    21. while(rs.next()){
    22. //获取数据
    23. int id = rs.getInt("id");
    24. String brandName = rs.getString("brand_name");
    25. String companyName = rs.getString("company_name");
    26. int ordered = rs.getInt("ordered");
    27. String description =rs.getString("description");
    28. int status = rs.getInt("status");
    29. //封装Brand对象
    30. brand = new Brand();
    31. brand.setId(id);
    32. brand.setBrandName(brandName);
    33. brand.setCompanyName(companyName);
    34. brand.setOrdered(String.valueOf(ordered));
    35. brand.setDescription(description);
    36. brand.setStatus(status);
    37. //装在对象
    38. brands.add(brand);
    39. }
    40. System.out.println(brands);
    41. //释放资源
    42. rs.close();
    43. pstmt.close();
    44. conn.close();
    45. }
      • 增删改
    1. /**
    2. * 添加
    3. */
    4. @Test
    5. public void testAdd() throws Exception {
    6. //接受页面提交的参数
    7. String brandName = "香飘飘";
    8. String companyName = "香飘飘";
    9. int ordered = 1;
    10. String description = "绕地球一周";
    11. int status = 1;
    12. //int id = 4; //修改数据库
    13. Properties prop = new Properties();
    14. prop.load(new FileInputStream("src/main/java/com/example/javaWeb/druid.properties"));
    15. //4. 获取数据库连接池对象
    16. DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    17. //5. 获取连接
    18. Connection conn = dataSource.getConnection();
    19. //定义SQL
    20. String sql = "INSERT INTO tb_brand(brand_name,company_name,ordered,description,status) values(?,?,?,?,?);";
    21. //修改数据
    22. //String sql = "update tb_brand set brand_name = ?,company_name=?,ordered = ?,description=?,status=?where id = ?;"
    23. //删除数据
    24. //String sql = "delete from tb_brand where id = ?"
    25. //获取pstmt对象
    26. PreparedStatement pstmt = conn.prepareStatement(sql);
    27. //设置参数
    28. pstmt.setString(1, brandName);
    29. pstmt.setString(2, companyName);
    30. pstmt.setInt(3, ordered);
    31. pstmt.setString(4, description);
    32. pstmt.setInt(5, status);
    33. //pstmt.setInt(6,id); //修改数据
    34. //执行sql
    35. int count = pstmt.executeUpdate();
    36. //处理结果
    37. System.out.println(count > 0);
    38. //释放资源
    39. pstmt.close();
    40. conn.close();
    41. }

  • 相关阅读:
    BLE Mesh中的Sequence number和IV Index
    Docker学习
    Apple m1 pro SourceTree 拉代码,AndroidStudio运行
    高等数学(第七版)同济大学 总习题五(后8题) 个人解答
    操作系统浅谈(二)
    2023年贵州省职业院校技能大赛(高职组)“软件测试”赛项竞赛规程
    mysql---视图详解
    多项式承诺:KZG
    Java I/O流相关操作
    计算机考研408-I/O方式大题答题流程
  • 原文地址:https://blog.csdn.net/jiayuzhen17qi/article/details/126526024