数据库开发基础(JDBC)

news/2024/11/17 3:08:45/文章来源:https://www.cnblogs.com/lmyfi/p/18200403

时间:2024-05-17日,星期五

数据库开发基础(Java)

课程内容

JDBC快速入门、使用JDBC开发细节、连接池与JDBC进阶使用

  • JDBC使用步骤

  • 数据库查询方法

  • 数据库写入方法

  • SQL注入攻击的应对

  • 连接池的使用

  • Apache Commons DBUtils

JDBC快速入门

JDBC是Java中为了去方便使用各种数据而创造出来的,在java开发过程中可以使用JDBC API进而对不同的数据库进行使用。

JDBC的优点

  • 统一的API,提供一致的开发过程

  • 易于学习,容易上手,代码结构稳定

  • 功能强大,执行效率高,可处理海量数据

JDBC开发流程

  1. 加载并注册JDBC驱动

  2. 创建数据库连接

  3. 创建Statement对象

  4. 遍历查询结果

  5. 关闭连接,释放资源

    public static void main(String[] args){
         Connection conn=null;
         try {
             //1. 加载并注册JDBC驱动
             Class.forName("com.mysql.cj.jdbc.Driver");
             //2. 创建数据库连接
             conn = DriverManager.getConnection(
                     "jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
             );
             //3. 创建Statement对象
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT * FROM employee");
             //4. 遍历查询结果
             while(rs.next()){
                 Integer eno= rs.getInt(1);
                 String name = rs.getString("ename");
                 Float salary = rs.getFloat("salary");
                 String dname = rs.getString("dname");
                 Date hiredate = rs.getDate("hiredate");
                 System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate);
             }
         }catch (Exception e){
             e.printStackTrace();
         }finally {
             try {
                 //5. 关闭连接,释放资源
                 if (conn != null && conn.isClosed() == false){
                     conn.close();
                 }
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         }
     }

 

JDBC开发流程细节

各数据库与连接字符串:

JDBC连接的对象Connection,通过TCP/IP协议,连通JDBC应用(Java程序)与MySQL数据库服务器的3306端口

  //2. 创建数据库连接
             conn = DriverManager.getConnection(
                     "jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
             )

其中的参数包括了连接字符串与数据库用户名和密码

MySQL连接字符串:

  • 格式:jdbc:mysql://主机ip:端口/数据库名?参数列表

  • 主机ip与端口是可选设置,默认值为127.0.0.1与3306

  • 参数列表采用url编码,格式:参数1=值1&参数2=值2&..

SQL注入攻击问题

  • SQL注入攻击是指利用SQL漏洞越权获取数据的黑客行为

  • SQL注入攻击根源是对原始SQL中的敏感字符做特殊处理

  • 解决方法:放弃Statement改用PrepareStatement处理SQL

    • Statement方法对符号单引号没有进行处理,会被SQL注入,使用PreStatement能防范SQL注入。

PrepareStatement

  • PrepareStatement预编译Statement是Statement的子接口

  • PrepareStatement对SQL进行参数化,预防SQL注入攻击

  • PreparedStatement比Statement执行效率更高

  •  String pdname = in.nextLine();
             String pdname = "市场部";//输入参数
             Connection conn=null;
             try {
                 //1. 加载并注册JDBC驱动
                 Class.forName("com.mysql.cj.jdbc.Driver");
                 //2. 创建数据库连接
                 conn = DriverManager.getConnection(
                         "jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
                 );
                 //3. 创建Statement对象
                 String sql = "SELECT * FROM employee WHERE dname=?";
                 PreparedStatement pStmt = conn.prepareStatement(sql);
                 pStmt.setString(1,pdname);
                 ResultSet rs = pStmt.executeQuery("SELECT * FROM employee WHERE dname='"+ pdname+"'");
                 //4. 遍历查询结果
                 while(rs.next()){
                     Integer eno= rs.getInt(1);
                     String name = rs.getString("ename");
                     Float salary = rs.getFloat("salary");
                     String dname = rs.getString("dname");
                     Date hiredate = rs.getDate("hiredate");
                     System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate);
                 }
             }catch (Exception e){
                 e.printStackTrace();
             }finally {
                 try {
                     //5. 关闭连接,释放资源
                     if (conn != null && conn.isClosed() == false){
                         conn.close();
                     }
                 } catch (SQLException throwables) {
                     throwables.printStackTrace();
                 }
             }

 

时间:2024-05-19日,星期天

JDBC进行数据库操作

将上面的数据库连接和数据库连接资源关闭方法进行封装,得到DBUtils,数据库工具文件

 package com.imooc.jdbc.common;
 ​
 import java.sql.*;
 ​
 public class DBUtils {
     /**
      * 获取数据库连接
      * @return返回数据库连接
      * @throws ClassNotFoundException
      * @throws SQLException
      */
     public static Connection getConnection() throws ClassNotFoundException, SQLException {
         //1. 加载并注册JDBC驱动
         Class.forName("com.mysql.cj.jdbc.Driver");
         //2. 创建数据库连接
         Connection conn = DriverManager.getConnection(
                 "jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
         );
         return conn;
     }
 ​
     /**
      * 关闭数据库连接相关资源
      * @param rs 数据库返回结果集
      * @param stmt 数据库预处理查询语句
      * @param conn 数据库连接
      */
     public static void closeConnection(ResultSet rs, Statement stmt, Connection conn){
         if (rs !=null){
             try {
                 //关闭结果连接,释放资源
                 rs.close();
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         }
         if (stmt != null){
             try {
                 //关闭连接,释放资源
                 stmt.close();
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         }
         try {
             //5. 关闭连接,释放资源
             if (conn != null && conn.isClosed() == false){
                 conn.close();
             }
         } catch (SQLException throwables) {
             throwables.printStackTrace();
         }
     }
 }

 

JDBC执行插入操作
 public class InsertCommand implements Command{
     @Override
     public void execute() {
         Scanner in = new Scanner(System.in);
         System.out.println("请输入员工编号:");
         int eno = in.nextInt();
         System.out.println("请输入员工姓名:");
         String ename = in.next();
         System.out.println("请输入员工薪资:");
         float salary = in.nextFloat();
         System.out.println("请输入隶属部门");
         String dname = in.next();
         Connection conn = null;
         PreparedStatement pStmt = null;
         try {
             conn = DBUtils.getConnection();
             String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";//插入语句
             pStmt = conn.prepareStatement(sql);
             pStmt.setInt(1,eno);
             pStmt.setString(2,ename);
             pStmt.setFloat(3,salary);
             pStmt.setString(4,dname);
             int cnt = pStmt.executeUpdate();//执行更新方法,返回插入的条数
             System.out.println("数据新增成功条数:"+cnt);
             System.out.println(ename+"已成功办理入职");
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (SQLException throwables) {
             throwables.printStackTrace();
         }finally {
             DBUtils.closeConnection(null,pStmt,conn);
         }
     }
 }
 ​
JDBC执行更新和删除操作

//更新

 /调整员工薪资
 public class UpdateCommand implements Command {
     @Override
     public void execute() {
         Scanner in = new Scanner(System.in);
         System.out.println("请输入要调整的员工编号");
         int eno = in.nextInt();
         System.out.println("请输入要调整到的薪资");
         float salary = in.nextFloat();
         Connection conn = null;
         PreparedStatement pStmt = null;
 ​
         try {
             conn = DBUtils.getConnection();
             String sql = "UPDATE employee SET salary=? WHERE eno=?";
             pStmt = conn.prepareStatement(sql);
             pStmt.setFloat(1,salary);
             pStmt.setInt(2, eno);
             int cnt = pStmt.executeUpdate();
             if (cnt == 1){
                 System.out.println("员工编号"+eno+"薪资已调整到"+salary);
             }else{
                 System.out.println("未找到员工编号为:"+eno+"的员工");
             }
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (SQLException throwables) {
             throwables.printStackTrace();
         }finally {
             DBUtils.closeConnection(null,pStmt,conn);
         }
     }
 }

//删除

 ​
 public class DeleteCommand implements Command{
     @Override
     public void execute() {
         Scanner in = new Scanner(System.in);
         System.out.println("请输入要删除的员工编号");
         int eno = in.nextInt();
         System.out.println("请输入要删除的员工姓名");
         String enmae = in.next();
         Connection conn = null;
         PreparedStatement pStmt = null;
 ​
         try {
             conn = DBUtils.getConnection();
             String sql = "DELETE FROM employee WHERE eno = ? AND ename = ?";
             pStmt = conn.prepareStatement(sql);
             pStmt.setInt(1,eno);
             pStmt.setString(2,enmae);
             int cnt = pStmt.executeUpdate();
             if (cnt == 1){
                 System.out.println("cnt:"+cnt);
                 System.out.println("员工编号"+eno+",姓名"+enmae+"的员工已删除");
             }else {
                 System.out.println("员工编号"+eno+",姓名"+enmae+"的员工未找到");
             }
 ​
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (SQLException throwables) {
             throwables.printStackTrace();
         }finally {
             DBUtils.closeConnection(null,pStmt,conn);
         }
     }
 }

更新和删除操作的方法主要区别是sql语句的不同,其它的内容大致相似。

JDBC的事务管理

JDBC中允许两种事务模式,分别是自动提交和手动提交模式

  • 自动提交事务模式

    • 自动提交模式是指每执行一次写操作SQL,自动提交事务

    • 自动提交开启方法:conn.setAutoCommit(true)

    • 自动事务是JDBC默认行为,此模式无法保证多数据一致性

  • 手动提交事务模式

    • 手动提交模式是指显式调用commit()与rollback()方法管理事务

    • 手动提交开启方法;conn.setAutoCommit(flase)

    • 手动提交事务可保证多数据一致性,但必须手动调用提交/回滚方法

//手动提交事务案例

 ​
 //JDBC事务管理,演示案例批量添加员工
 public class TransactionSample {
     public static void main(String[] args) {
         Connection conn = null;
         PreparedStatement pStmt = null;
 ​
         try {
             conn = DBUtils.getConnection();
             conn.setAutoCommit(false);//开启jdbc手动提交事务,,自动提交事务时默认为true
             String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)";
             pStmt = conn.prepareStatement(sql);
             for (int i=1000; i<2000; i++){
                 if (i==1005){
 //                    throw new RuntimeException("插入失败"); //注释后,不抛异常,正常执行
                 }
                 pStmt.setInt(1,i);
                 pStmt.setString(2,"员工"+i);
                 pStmt.setFloat(3,4000f);
                 pStmt.setString(4,"市场部");
                 pStmt.executeUpdate();
             }
             conn.commit();//手动提交情况下才能显式使用
         } catch (Exception e) {
             try {
                 conn.rollback();//回滚数据,手动提交情况下才能使用
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         } finally {
             DBUtils.closeConnection(null,pStmt,conn);
         }
     }
 }

JDBC对时间类型的处理

//将String类型转为java.sql.Date,分为两步,分别是

         //1.String转为java.util.Date
         java.util.Date udHiredate = null;
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         try {
             udHiredate = sdf.parse(strHireadate);
         } catch (ParseException e) {
             e.printStackTrace();
         }
         //2.java.util.Date转为java.sql.Date
         long time = udHiredate.getTime();//获取自1970到现在的毫秒数
         java.sql.Date sdHiredate = new java.sql.Date(time);

 

数据库连接池

阿里巴巴Druid连接池

Druid是阿里巴巴开源连接池组件,Druid对数据库连接进行有效管理与重用,最大化程序执行效率,连接池负责创建管理连接,程序只负责取用与归还

连接Druid连接池(配置和使用)
 //配置使用Druid连接池
 public class DruidSample {
     public static void main(String[] args) {
 ​
         //1.加载属性文件
         Properties properties = new Properties();
         String propertyFile = DruidSample.class.getResource("/druid-config.properties").getPath();
         try {
             propertyFile = new URLDecoder().decode(propertyFile, "UTF-8");//解析文件,避免错误
             properties.load(new FileInputStream(propertyFile));
         } catch (Exception e) {
             e.printStackTrace();
         }
         Connection conn = null;
         PreparedStatement pStmt = null;
         ResultSet rs = null;
 ​
         try {
             //2.获取DataSource数据源对象
             DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
             //创建数据库连接
             conn = dataSource.getConnection();
             pStmt = conn.prepareStatement("select * from employee limit 0,5");
             rs = pStmt.executeQuery();
             while(rs.next()){
                 Integer eno= rs.getInt(1);
                 String name = rs.getString("ename");
                 Float salary = rs.getFloat("salary");
                 String dname = rs.getString("dname");
                 Date hiredate = rs.getDate("hiredate");
                 System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate);
             }
         } catch (Exception e) {
             e.printStackTrace();
         }finally {
             DBUtils.closeConnection(rs,pStmt,conn);
         }
 ​
     }
 }

 

Apache Commons DBUtils

  • commons-dbutils是Apache提供的开源JDBC工具类库

  • 它是对JDBC的简单封装,学习成本极低

  • 使用commons-dbutils可以极大简化JDBC编码工作量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/708901.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视野修炼-技术周刊第84期 | Mako

① npmmirror 下线 unpkg 服务 ② Mako - 又一基于 Rust 的构建工具 ③ Icnes - 图标集合检索 ④ go-masonry-gallery - 图片瀑布流页面生成 ⑤ Color Pick - 在线从图片中提取颜色的 ⑥ 制作 CSS 形状的现代指南 ⑦ 针对前端初学者的项目合集 ⑧ Jan - 本地运行大模型客户端欢…

jQuery2-动画技术入门指南-全-

jQuery2 动画技术入门指南(全)原文:zh.annas-archive.org/md5/71BE345FA56C4A075E859338F3DCA6DA 译者:飞龙 协议:CC BY-NC-SA 4.0序言 jQuery 是一个跨浏览器的 JavaScript 库,旨在简化 HTML 的客户端脚本编写,并且是当今最流行的 JavaScript 库。利用 jQuery 提供的功…

EDP .Net开发框架--业务模型

EDP是一套集组织架构,权限框架【功能权限,操作权限,数据访问权限,WebApi权限】,自动化日志,动态Interface,WebApi管理等基础功能于一体的,基于.net的企业应用开发框架。通过友好的编码方式实现数据行、列权限的管控。平台下载地址:https://gitee.com/alwaysinsist/edp…

CentOS挂载硬盘

1.查看新添加的硬盘 fdisk -l2.挂载到/data目录 mount /dev/vdb1 /data 3.设置开机自启 vi /etc/fstab 在最后一行添加 /dev/vdb1 /data ext4 defaults 0 0

sed编辑器和awk

目录1.sed的执行过程(1)sed 的工作流程(2)打印内容(3)删除(4)替换(5)打印被修改的行(6)插入(7)复制粘贴2.awk(1)工作原理 1.sed的执行过程 sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处…

“复兴杯”2023第四届大学生网络安全精英赛排位赛 Writeup

时间跟全国信安初赛重了(),不过也是第一次在CTF AK了( 个人信息 个人排名:15 解题过程 1观察代码,使用科学技术法进行绕过,2.023e3也就是2.023*10^3=2023,弱比较时会化为2023,但是运算时后并不绝对等于2024。 输入得到flag。2 打开网站可以看到电脑账号是ly,使用过滤…

基于webapi的websocket聊天室(四)

上一篇实现了多聊天室。这一片要继续改进的是实现收发文件,以及图片显示。 效果问题 websocket本身就是二进制传输。文件刚好也是二进制存储的。 文件本身的传输问题不太,但是需要传输文件元数据,比如文件名和扩展名之类的。这很必要,如果我们想知道怎么展示这个文件的话。比…

嵌入式Linux中的LED驱动控制(以野火STM32MP157开发板为例)

在嵌入式Linux系统中,由于从硬件到软件都是自己定制的,所以很多时候需要对自己定义的设备编写驱动程序。本例就以野火STM32MP157开发板为例,讨论如何控制开发板上三个LED的亮灭。 先来看一下LED部分的电路原理图,如下所示。从上图中可以看到,三个RGB颜色的二极管采用共阳接…

BUUctf xor

0x01 关于xor xor,即为计算机中的异或计算,相同为0,不同为1。 下面是关于异或加密的四个定理A ^ 0 = A A ^ A = 0 (A ^ B) ^ C = A ^ (B ^ C) (B ^ A) ^ A = B ^ 0 = B // 明文 B;密码 A观察可知,经历异或加密后的密文,再次进行异或算法即可得到明文。 0x02 题解 先丢进…

解决VSCode中Debug和运行路径不一致的

哈喽,大家好,我是木头左!背景介绍 在Visual Studio Code(简称VSCode)中进行开发时,经常需要使用到调试(Debug)功能。然而,有时候会发现,当尝试调试程序时,程序的运行路径与预期不符。这通常会导致程序无法正确读取文件或访问资源,从而影响调试过程。为了解决这个问…

DockerDesktop安装指南以及Windows下WSL2和 Hyper-V相关问题追查

文章原创不易,转载请注明来源 ,谢谢! 一、 问题 周末在家,给自己的老的台式机安装DockerDesktop。 电脑配置是处理器 Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz 3.30 GHz机带 RAM 16.0 GB (15.9 GB 可用)系统类型 64 位操作系统, 基于 x64 的处理器版本 Windows 10 专业版…

软件设计原则—接口隔离原则

B类需要方法1好处是b类继承A类后就有了方法1的功能,问题是B类被迫有了它不使用的方法2 这个其实是根据方法的职责细分接口,只需要依赖其中一个接口就可以了客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上。 下面看一个例子来理解接口隔…