前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDBC入坑笔记

JDBC入坑笔记

作者头像
Breeze.
发布2022-06-05 12:15:08
2430
发布2022-06-05 12:15:08
举报

什么是JDBC

Java数据库连接 - Java DataBase Connectivity JDBC可以让Java通过程序操作关系型数据库 JDBC基于驱动程序实现与数据库的连接与操作

image-20220516171753054
image-20220516171753054

JDBC的优点

  • 统一的API,提供开发过程
  • 易于学习,容易上手,代码结构稳定
  • 功能强大,执行效率高,可处理海量数据

快速上手JDBC

image-20220516172442384
image-20220516172442384

JDBC开发细节

获取JDBC驱动Jar

MySQL :: MySQL Connectors

创建数据库连接代码

image-20220516183104055
image-20220516183104055
  • Calss.forName用于加载指定的JDBC驱动类,本质是通知JDBC注册这个驱动类,驱动由数据库厂商自行开发,连接字符串也不同
image-20220516183941981
image-20220516183941981

数据库连接配置

DriverManager

DriverManager:用于注册/管理JDBC驱动程序

DriverManager.getConnection(连接字符串,用户名,密码)

返回值Connection对象,对应数据库的物理网络连接

Connection 对象

Connection对象用于JDBC与数据库的网络通信对象

java.sql.Connection是一个接口,具体由驱动厂商实现

所有数据库的操作都建立在Connection基础之上

image-20220516192835417
image-20220516192835417

MySQL连接字符串

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

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

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

MySQL连接字符串常用参数

image-20220516194149732
image-20220516194149732

JDBC的查询操作及SQL注入漏洞

PreparedStatement:主要解决SQL注入问题

SQL注入攻击

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

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

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

PreparedStatement

PreparedStatement 预编译 Statement 是 Statement 的子接口

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

PreparedStatement 比 Statement 执行效率更高

image-20220519141326769
image-20220519141326769
image-20220519141443786
image-20220519141443786

错误使用方式

image-20220519145211537
image-20220519145211537

JDBC工具类的抽取及增删改查

封装DbUtils工具类

代码语言:javascript
复制
 public class DbUtils {
     /**
      * 创建新的数据库连接
      * @return 新的Connection对象
      * @throws SQLException
      * @throws ClassNotFoundException
      */
     public static Connection getConnection() throws SQLException, ClassNotFoundException {
         //1. 加载并注册JDBC驱动
         Class.forName("com.mysql.cj.jdbc.Driver");
         //2. 创建数据库连接
         String url = "jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode=true&characterEncoding=UTF-8&severTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
         Connection conn = DriverManager.getConnection(url, "root", "123456");
         return conn;
     }

     /**
      * 关闭连接,释放资源
      * @param rs 结果集对象
      * @param stmt Statement对象
      * @param conn Connection对象
      */
     public static void closeConnection(ResultSet rs, Statement stmt, Connection conn) {
         //5. 关闭连接,释放资源
         try {
             if (rs != null) {
                 rs.close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
         try {
             if (stmt != null) {
                 stmt.close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
         try {
             if (conn != null && !conn.isClosed()) {
                 conn.close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
 }

JDBC实现新增数据

image-20220519162650384
image-20220519162650384
代码语言:javascript
复制
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(); //所有写操作都用 executeUpdate,且返回值为整型,代表本次执行所影响的记录数

实现JDBC更新与删除数据

image-20220519174159339
image-20220519174159339
代码语言:javascript
复制
            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("运功薪资以调成完成!");
            } else {
                System.out.println("没有找到编号:"+eno+",员工的数据。");
            }
image-20220519174312618
image-20220519174312618
代码语言:javascript
复制
            conn = DbUtils.getConnection();
            String sql = "delete from employee where eno = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, eno);
            int cnt = pstmt.executeUpdate();
            if (cnt == 1) {
                System.out.println("员工数据以删除!");
            } else {
                System.out.println("没有找到编号:"+eno+",员工的数据。");
            }

JDBC中的事务管理

事务是以一种可靠的、一致的方式,访问和操作数据库的程序单元 事务依赖于数据库实现,MySQL通过事务区作为数据缓冲地带

image-20220519204422648
image-20220519204422648
image-20220519204639376
image-20220519204639376
image-20220519204823342
image-20220519204823342
image-20220519205113038
image-20220519205113038
image-20220519205159088
image-20220519205159088

手动事务开发

代码语言:javascript
复制
public class TransactionSample {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = DbUtils.getConnection();
            //JDBC默认使用自动提交的模式
            conn.setAutoCommit(false);//关闭自动提交
            String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
            for (int i = 1000; i < 1020; i++) {
                if (i == 1005) {
                    // throw new RuntimeException("插入失败");
                }
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, i);
                pstmt.setString(2, "员工" + i);
                pstmt.setFloat(3, 4000f);
                pstmt.setString(4, "市场部");
                pstmt.executeUpdate();
            }
            conn.commit();//提交数据
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if (conn != null && !conn.isClosed()) {
                    conn.rollback();//数据回滚
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            DbUtils.closeConnection(null, pstmt, conn);
        }
    }
}

JDBC的日期处理及批量处理

Date日期对象的处理

代码语言:javascript
复制
        //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(strHiredate);
        } 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);

数据批处理

代码语言:javascript
复制
            long startTime = new Date().getTime();
            conn = DbUtils.getConnection();
            //JDBC默认使用自动提交的模式
            conn.setAutoCommit(false);//关闭自动提交
            String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
            for (int i = 100000; i < 200000; i++) {
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, i);
                pstmt.setString(2, "员工" + i);
                pstmt.setFloat(3, 4000f);
                pstmt.setString(4, "市场部");
                pstmt.executeUpdate();
            }
            conn.commit();//提交数据
            long endTime = new Date().getTime();
            System.out.println("tc1执行时长:"+ (endTime-startTime));
代码语言:javascript
复制
            long startTime = new Date().getTime();
            conn = DbUtils.getConnection();
            //JDBC默认使用自动提交的模式
            conn.setAutoCommit(false);//关闭自动提交
            String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
            pstmt = conn.prepareStatement(sql);
            for (int i = 200000; i < 300000; i++) {
                pstmt.setInt(1, i);
                pstmt.setString(2, "员工" + i);
                pstmt.setFloat(3, 4000f);
                pstmt.setString(4, "市场部");
                pstmt.addBatch();//将参数加入批处理任务
//                pstmt.executeUpdate();
            }
            pstmt.executeBatch();//指向批处理任务
            conn.commit();//提交数据
            long endTime = new Date().getTime();
            System.out.println("tc2执行时长:"+ (endTime-startTime));

连接池与JDBC进阶使用

阿里巴巴Druid连接池

Druid是阿里巴巴开源连接池组件,是最好的连接池之一

Druid对数据库连接进行有效的管理与重用,最大化程序执行效率

image-20220521185441027
image-20220521185441027

Druid连接池配置与使用

代码语言:javascript
复制
/**
 * Druid连接池配置与使用
 */
public class DruidSample {
    public static void main(String[] args) {
        //1.加载属性文件
        //创建Properties类,利用Properties对象保存druid-config.properties配置文件信息
        Properties properties = new Properties();
        //当前类.cslass.getReource("/文件名").getPath() 表示获取当前类路径下对应文件的路径,用String类型保存
        String propertyFile = DruidSample.class.getResource("/druid-config.properties").getPath();
        try {
            //将propertyFile转回到UTF-8
            //空格 -> %20 c:\java%20code\druid-config.properties
            //URLDecoder().decode()将%20还原到原来的空格 c:\java code\druid-config.properties
            propertyFile = new URLDecoder().decode(propertyFile, "UTF-8");
            //使用properties.load()方法,加载propertyFile路径文件
            properties.load(new FileInputStream(propertyFile));
        } catch (Exception e) {
            e.printStackTrace();
        }

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            //2.获取DateSource数据源对象
            //利用DruidDataSourceFactory数据源工厂.createDataSource,将已载入的properties对象放入。
            //方法返回时的数据源DataSource 选用javax.sql下的
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            //3.创建数据库连接
            conn = dataSource.getConnection();
            pstmt = conn.prepareStatement("select * from employee limit 0,10");
            rs = pstmt.executeQuery();
            while (rs.next()) {
                Integer enoId = rs.getInt(1);
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println("部门:" + dname + " 编号:" + enoId + " 姓名:" + ename + " 工资:" + salary);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DbUtils.closeConnection(rs, pstmt, conn);
        }
    }
}

不使用连接池:conn.close()关闭连接,使用连接池:conn.close()将连接回收至连接池

这个需要配置druid-config.properties文件,如果在程序运行中达到了maxActive上线,其余的程序一直会进入等待,等待其他正在使用连接程序调用close方法将这个数据库连接进行回收。

代码语言:javascript
复制
#初始的尺寸
initialSize=10
#最多不得大于20
maxActive=20

Druid连接池的配置连接数量的初始值为什么要和最大值保持一致?

是因为在我们日常工作的时候,做为应用程序,最好在一开始就把所有的连接和资源都分配好,用户进来后直接分配现成的资源避免出现重新创建资源的情况,这样对整体的程序管理和性能都有帮助。

扩展知识:C3P0连接池

image-20220522152342482
image-20220522152342482

在C3P0中强制配置文件名叫c3p0-config.xml文件,并且放在根路径上,在创建ComboPooledDataSource对象的时候会自动加载XML文件

并且根据XML文件,创建DataSource数据源对象

image-20220522152400030
image-20220522152400030

Commons DBUtils使用入门

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

查找

image-20220522160808919
image-20220522160808919

更新

image-20220522163603655
image-20220522163603655
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是JDBC
    • 快速上手JDBC
      • JDBC开发细节
        • 数据库连接配置
          • DriverManager
          • Connection 对象
          • MySQL连接字符串
          • MySQL连接字符串常用参数
      • JDBC的查询操作及SQL注入漏洞
        • SQL注入攻击
          • PreparedStatement
            • 错误使用方式
            • JDBC工具类的抽取及增删改查
              • 封装DbUtils工具类
                • JDBC实现新增数据
                  • 实现JDBC更新与删除数据
                  • JDBC中的事务管理
                    • 手动事务开发
                    • JDBC的日期处理及批量处理
                      • Date日期对象的处理
                        • 数据批处理
                        • 连接池与JDBC进阶使用
                          • 阿里巴巴Druid连接池
                            • Druid连接池配置与使用
                          • 扩展知识:C3P0连接池
                            • Commons DBUtils使用入门
                            相关产品与服务
                            云数据库 SQL Server
                            腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档