Java基础_JDBC

news2024/12/25 8:53:44

JDBC

  • 概述
  • 步骤
  • 项目创建
    • 流程
    • 代码改进
  • 使用Statement的问题:SQL注入
    • (1)SQL注入
      • (2)PreparedStatement
        • 1、防止SQL注入
        • 2、批处理
  • 事务
  • 连接池
    • 建立数据库连接
    • 实现
  • 日志

概述

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。我们通常说的JDBC是面向关系型数据库的。

JDBC

在这里插入图片描述

步骤

  1. 加载驱动Driver
  2. 创建数据库连接Connection
  3. 创建SQL命令发送器Statement
  4. 发送SQL命令,获取结果
  5. 处理结果
  6. 关闭资源(结果集ResultSet、Statement、Connection)

项目创建

流程

  1. 导入jar包【数据库厂商实现JDBC相关接口的驱动jar包】
    MySQL_jar
    在这里插入图片描述

  2. 准备信息

String url="jdbc:mysql://127.0.0.1:3306/${database_name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
String user="${user}";
String password="${password}";
String sql="${sql}";
  1. Driver(加载、注册) -> Connection【使用准备信息】-> 获取Statement -> 执行SQL ->处理结果集 -> 释放资源
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);

Connection connection = DriverManager.getConnection(url, user,password );

Statement statement = connection.createStatement();

// 返回
// int:影响行数(增、删、改)
// ResultSet:查询结果集
statement.executeUpdate(sql);

xxx.close();// 后获取的先关闭

代码改进

(1)使用注解加载Driver

private static String driver ="com.mysql.cj.jdbc.Driver";

Class.forName(driver);

(2)使用try-with-resources释放资源

try (Connection connection = DriverManager.getConnection(url, user, password);
	Statement statement = connection.createStatement()) {
	
	Class.forName(driver);
    statement.execute(sql));
    
} catch (Exception e) {
	e.printStackTrace();
}

(3)省略Class.forName(driver);

在调用 getConnection 方法时,DriverManager 会试着从初始化时加载的那些驱动程序以及使用与当前 applet 或应用程序相同的类加载器显式加载的那些驱动程序中查找合适的驱动程序。

(4)配置文件:参数优化
在这里插入图片描述

jdbc.properties

## key=value
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mytestdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
user=root
password=123456
initSize=1
maxSize=1

PropertiesUtil工具类:

public class PropertiesUtil {
    private Properties properties;
    public PropertiesUtil(String path){
        properties=new Properties();
        InputStream inputStream = this.getClass().getResourceAsStream(path);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public String getProperties(String key){
        return properties.getProperty(key);
    }
}

JDBC修改:

PropertiesUtil propertiesUtil=new PropertiesUtil("/jdbc.properties");
driver=propertiesUtil.getProperties("driver");
url=propertiesUtil.getProperties("url");
user=propertiesUtil.getProperties("user");
password=propertiesUtil.getProperties("password");
initSize=Integer.parseInt(propertiesUtil.getProperties("initSize"));
maxSize=Integer.parseInt(propertiesUtil.getProperties("maxSize"));

使用Statement的问题:SQL注入

(1)SQL注入

SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序。

(2)PreparedStatement

1、防止SQL注入

PreparedStatement使用?作为参数的占位符。

String sql="select * from account where username = ? and password = ?";

//在获取PreparedStatement对象时已经传入SQL语句
try(Connection connection =DriverManager.getConnection(url, user,password);
    PreparedStatement preparedStatement=connection.prepareStatement(sql);){
    
	Class.forName(driver);
	/*
	* 如果SQL语句中有?作为参数占位符号,那么要在执行CURD之前先设置参数
	* 通过set***(问号的编号,数据) 方法设置参数
	* */

	//设置参数
	preparedStatement.setString(1,username );
	preparedStatement.setString(2,pwd );

	//执行CURD,这里不需要再传入SQL语句
	resultSet = preparedStatement.executeQuery(); 
	
}catch (Exception e){
	e.printStackTrace();
}finally {
	//关闭resultSet
	if(null != resultSet){
		try {
			resultSet.close();
		} catch (SQLException e){
			e.printStackTrace();
        }
    }
}
2、批处理
  • statement语句对象实现批处理有如下问题:
    • 缺点:采用硬编码效率低,安全性较差。
    • 原理:硬编码,每次执行时相似SQL都会进行编译
  • PreparedStatement+批处理:
    • 优点:语句只编译一次,减少编译次数。提高了安全性(阻止了SQL注入)
    • 原理:相似SQL只编译一次,减少编译次数
    • 注意: 需要设置批处理开启&rewriteBatchedStatements=true【url】
for (int i = 1; i <= 10663; i++) {
	preparedStatement.setString(1, "name");
	preparedStatement.setString(2, "loc");
	preparedStatement.addBatch();// 将修改放入一个批次中
	
	if(i%1000==0){
		preparedStatement.executeBatch();
		preparedStatement.clearBatch();// 清除批处理中的数据
    }
}
/*
* 整数数组中的元素代表执行的结果代号
* SUCCESS_NO_INFO -2
* EXECUTE_FAILED  -3
* */
/*int[] ints = */
preparedStatement.executeBatch();
preparedStatement.clearBatch();

事务

在逻辑上一组不可分割的操作。由多个sql语句组成,多个sql语句要么全都执行成功,要么都不执行。

ACID(原子性 一致性 隔离性 持久性)

如何让多个数据库操作成为一个整体:实现要么全都执行成功,要么全都不执行。

在JDBC中,事务操作是自动提交
【一条对数据库的DML(insert、update、delete)代表一项事务操作。操作成功后,系统将自动调用commit()提交,否则自动调用rollback()回滚。】

java.sql.Connection

  • 禁止自动提交:setAutoCommit(false)
  • 提交:commit()
  • 回滚:rollback()【异常捕获时调用】
  • 设置回滚点:setSavepoint() -->savepoints{集合中存储}–>获取需要的回滚点–>rollback(savepoint)

连接池

建立数据库连接

  • 传统连接:
    • 调用Class.forName()方法加载数据库驱动;调用DriverManager.getConnection()方法建立连接。
    • 问题:
      • 每次执行DML / DQL 都要创建一次Connection对象,执行完毕后Connection对象都要被销毁。
      • 没有复用,消耗系统资源
  • 连接池:
    • 预先创建多个数据库连接对象,将连接对象保存在连接池中。【请求到来->从池中取出连接对象;请求完毕->客户程序调用close()将对象放回池中】
    • 复用->减少资源消耗;多线程请求,缓解压力

实现

(1)定义连接池

public class MyConnectionPool {
    private static String driver ="com.mysql.cj.jdbc.Driver";
    private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
    private static String user="root";
    private static String password="root";
    private static int initSize=1;
    private static int maxSize=1;
    
    private static LinkedList<Connection> pool;
    
    static{
        // 加载驱动
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } 
        
        // 私有的初始化一个链接对象的方法
		private static Connection initConnection(){
            try {
                 return DriverManager.getConnection(url,user,password);
            } catch (SQLException e) {
                 e.printStackTrace();
            }
            return null;
        }

        // 初始化pool
        pool=new LinkedList<Connection>();
        // 创建5个链接对象
        for (int i = 0; i <initSize ; i++) {
            Connection connection = initConnection();
            if(null != connection){
                pool.add(connection);
                System.out.println("初始化连接"+connection.hashCode()+"放入连接池");
            }
        }
    }

    // 共有的向外界提供链接对象的
    public static Connection getConnection(){
        Connection connection =null;
        if(pool.size()>0){
            connection= pool.removeFirst();// 移除集合中的第一个元素
            System.out.println("连接池中还有连接:"+connection.hashCode());
        }else{
            connection = initConnection();
            System.out.println("连接池空,创建新连接:"+connection.hashCode());
        }
        return connection;
    }
    // 共有的向连接池归还连接对象的方法
    public static void returnConnection(Connection connection){
        if(null != connection){
            try {
                if(!connection.isClosed()){
                    if(pool.size()<maxSize){
                        try {
                            connection.setAutoCommit(true);// 调整事务状态
                            System.out.println("设置连接:"+connection.hashCode()+"自动提交为true");
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        pool.addLast(connection);
                        System.out.println("连接池未满,归还连接:"+connection.hashCode());
                    }else{
                        try {
                            connection.close();
                            System.out.println("连接池满了,关闭连接:"+connection.hashCode());
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }else{
                    System.out.println("连接:"+connection.hashCode()+"已经关闭,无需归还");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println("传入的连接为null,不可归还");
        }
    }
}

日志

log4j2官网
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习:驱动现代交通运输革命的AI智慧引擎

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

POCEXP编写—多线程

POC&EXP编写—多线程 1. 前言2. 多进程&多线程2.1. 多进程2.1.1. 案例 2.2. 多线程2.2.1. 案例&#xff1a; 2.3. POC的案例&#xff08;模板&#xff09; 3. UA头设置3.1. 随机UA头3.1.1. 案例3.1.2. 模板拼接 4. 代理Proxy4.1. 单代理案例4.2. 多代理案例4.2.1. 请求…

2024年最新linux安装harbor

linux安装harbor Harbor官方介绍这里就不照搬了&#xff0c;说直白点&#xff1a;Harbor就是私有的 Docker Hob 镜像仓库。 前置条件&#xff1a;安装好docker,docker-compose 1、安装harbor离线包&#xff08;在线安装形式不稳定&#xff0c;由于网络原因中间可能中断&…

C++ 小游戏:战斗之旅

一、游戏名称&#xff1a;战斗之旅 游戏规则 角色选择&#xff1a;玩家可以选择不同的角色&#xff0c;每个角色都有不同的属性和技能。商城&#xff1a;玩家可以访问商城购买不同的装备&#xff0c;包括武器和回复物品。战斗&#xff1a;玩家可以与其他角色进行战斗。在战斗…

盲人定位设备:为视障人士独立出行铺设智慧之路

在快速发展的数字时代&#xff0c;科技的每一次跃进都在悄然改变我们的生活方式。对于盲人朋友而言&#xff0c;一款名为“蝙蝠避障”集实时避障于一身的盲人定位设备&#xff0c;正成为他们探索世界、实现独立出行的有力助手。这款设备&#xff0c;不仅重新定义了无障碍出行的…

YOLOv8+PyQt5输电线路缺陷检测(目前最全面的类别检测,可以从图像、视频和摄像头三种路径检测)

1.效果视频&#xff1a;YOLOv8PyQt5输电线路缺陷检测&#xff08;目前最全面的类别检测&#xff0c;可以从图像、视频和摄像头三种路径检测&#xff09;_哔哩哔哩_bilibili 资源包含可视化的输电线路缺陷检测系统&#xff0c;可识别图片和视频当中出现的五类常见的输电线路缺陷…

新书速览|ChatGLM3大模型本地化部署、应用开发与微调

实战文本生成、智能问答、信息抽取、财务预警应用开发&#xff0c;掌握ChatGLM3大模型部署、开发与微调技术 01 本书内容 《ChatGLM3大模型本地化部署、应用开发与微调》作为《PyTorch 2.0深度学习从零开始学》的姊妹篇&#xff0c;专注于大模型的本地化部署、应用开发以及微…

Linux基本指令(3)

目录 时间相关的指令&#xff1a; 1.在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff0c;格式设定为一个加好后接数个标记&#xff0c;其中常用的标记列表如下&#xff1a; 2.在设定时间方面&#xff1a; 3.时间戳&#xff1a; Cal指令&#xff1a; find指令&a…

Kubernetes 声明式语言 YAML

什么是 YAML YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种可读的数据序列化语言&#xff0c;通常用于配置文件、数据序列化和交换格式。YAML 的设计目标是易读易写&#xff0c;并且能够映射到动态语言中的数据结构 YA加粗样式ML 是 JSON 的超集&#xff0…

纯血鸿蒙APP实战开发——Navigation实现多设备适配案例

介绍 在应用开发时&#xff0c;一个应用需要适配多终端的设备&#xff0c;使用Navigation的mode属性来实现一套代码&#xff0c;多终端适配。 效果图预览 使用说明 将程序运行在折叠屏手机或者平板上观看适配效果。 实现思路 本例涉及的关键特性和实现方案如下&#xff1a…

MyBatis(注解方式操作)

文章目录 1.注解方式操作文件目录1.快速入门&#xff08;完整步骤&#xff09;1.pom.xml&#xff08;完整&#xff09;2.resources/jdbc.properties外部配置文件&#xff08;根据实际情况修改参数&#xff09;3.在resources/mybatis-config.xml&#xff08;完整&#xff09;中配…

仓库管理系统(WMS)是什么?有哪些功能?

阅读本文&#xff0c;你将了解&#xff1a;1、仓库管理&#xff08;WMS&#xff09;是什么&#xff1f; 2、仓库管理系统&#xff08;WMS&#xff09;有什么功能 3、使用仓库管理系统能给企业带来什么好处 一、仓库管理系统是什么 WMS&#xff0c;全称Warehouse Management S…

借助Aspose.SVG图像控件,在线将 PNG 转换为 XML

Aspose.SVG for .NET 是用于SVG文件处理的灵活库&#xff0c;并且与其规范完全兼容。API可以轻松加载&#xff0c;保存和转换SVG文件&#xff0c;以及通过其文档对象模型&#xff08;DOM&#xff09;读取和遍历文件的元素。API独立于任何其他软件&#xff0c;使开发人员无需使用…

BGP配置和应用案例

策略路由的配置步骤 l 策略路由的配置步骤如下&#xff1a; 创建route-map 通过ACL匹配感兴趣的数据&#xff0c;定义策略动作 在指定接口下通过ip policy 命令应用route-map l 最终实现对通过该接口进入设备的数据进行检查&#xff0c;对匹配的数据执行规定的策略…

注意力机制(四)(多头注意力机制)

​&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;《深度学习基础知识》 相关专栏&#xff1a; ⚽《机器学习基础知识》 &#x1f3d0;《机器学习项目实战》 &#x1f94e;《深度学习项目实…

如何使用python自动修改图片

如何使用python自动修改图片 首先&#xff1a; 要使用Python代码自动修改图片,你可以使用 imageio和matplotlib库.以下是一个简单的示例代码,演示如何调整图片尺寸. 确保已经安装了imageio和matplotlib库.如果没有安装,可以使用以下命令安装 pip install imageio matplotli…

10G MAC层设计系列-(2)MAC RX模块

一、概述 MAC RX模块的需要进行解码、对齐、CRC校验。 因为在空闲的时候10G PCS/PMA会一直向外吐空闲符&#xff08;x07&#xff09;所以需要根据开始符、结束符将有效数据从码流中截取&#xff0c;也就是解码。 因为开始字符的所在位置有两种形式&#xff0c;而结束字符的位…

C语言 | Leetcode C语言题解之第50题Pow(x,n)

题目&#xff1a; 题解&#xff1a; double myPow(double x, int n){if(n 0 || x 1){return 1;}if(n < 0){return 1/(x*myPow(x,-(n1)));}if(n % 2 0){return myPow(x*x,n/2);}else{return x*myPow(x*x,(n - 1)/2);} }

Node私库Verdaccio使用记录,包的构建,推送和拉取

Node私库Verdaccio使用记录&#xff0c;包的构建&#xff0c;推送和拉取 Verdaccio是一个轻量级的私有npm代理注册中心&#xff0c;它可以帮助你在本地搭建一个npm仓库&#xff0c;非常适合企业内部使用。通过使用Verdaccio&#xff0c;你可以控制和缓存依赖包&#xff0c;提高…

QT:信号和槽

文章目录 信号和槽connect函数槽自定义槽第一种第二种 信号和槽 这里的信号和Linux的信号一样吗&#xff1f; 答案是差不多&#xff0c;但是也有一定的区别&#xff0c;而且也是两个不同的概念 信号有三个概念&#xff0c;一个是信号源&#xff0c;这个信号是由谁发送的&…