JDBC

本文深入探讨了JDBC的工作原理及其在Java中如何实现数据库连接。详细介绍了JDBC的结构,包括DriverManager、Connection、Statement和ResultSet等核心组件的作用。此外,还讲解了PreparedStatement的使用,以增强代码的可读性、效率和安全性,有效防止SQL注入。最后,文章讨论了数据库连接池的重要性,特别是在提高资源利用效率和系统响应速度方面的作用。

JDBC

JDBC的结构

​ JDBC(Java DataBase Connectivity),Java数据库连接,是一种用于Sql语句的Java API,可以为多种数据库提供同一访问。它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

图1

 JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接。
JDBC核心(接口)介绍

JDBC中的核心类有:DriverManager、Connection、Statement和ResultSet。
DriverManager的作用有两个:1>注册驱动:让JDBC知道要使用哪个驱动;2>获取Connection,成功获取到Connection,说明数据库连接成功。
Connection是连接对象,最为重要的一个用途是获取Statement
Statement用来向数据库发送SQL语句。

  • void executeUpdate(String sql):执行更新操作(insert、update、delete等);
  • ResultSet executeQuery(String sql):执行查询操作,数据库在执行查询后会把查询结果,查询结果就是ResultSet;

ResultSet对象标识查询的结果集,只有执行查询操作后才会产生。

  • boolean next():使“行光标”移动到下一行,并返回移动后的行是否存在;
  • XXX getXXX(int col):获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。
连接数据库的步骤

JDBC主要做四件事。

​ 1>加载对应的数据库驱动

Class.forName("com.mysql.jdbc.Driver");//以Mysql为例

​ 2>与数据库建立连接

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

​ 3>发送操作语句

Statement stmt = con.createStatement();

​ 4>执行并处理返回结果

ResultSet rs = stmt.executeQuery(sql);//查询语句
int m = stmt.executeUpdate(sql);//增、删、改语句,返回值表示执行这条SQL语句所影响的行数

图2

PreparedStatement

​ PreparedStatement是Statement的子接口.

使用PreparedStatement的好处:
1>提高代码的可读性和可维护性。
2>提高效率。如果Sql被多次执行,只是其中的参数不同,使用PreparedStatement最好。PreparedStatement第一次消耗较高,后续的重复执行效率提升(缓存的作用)
3>防止Sql注入

Sql注入

​ 数据库中的用户数据如下:

图3

登录方法

	/**
	 * 登录 使用username和password查询数据 如果有结果返回true 如果没有结果,返回false
	 * 
	 * @param username
	 * @param password
	 * @return
	 */
	public boolean login(String username, String password) {
		String driverClassName = "com.mysql.jdbc.Driver";
		String url = "jdbc:mysql://localhost:3306/mydb";
		String mysqlUsername = "root";
		String mysqlPassword = "******";
		Connection con = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			Class.forName(driverClassName);
			con = DriverManager
					.getConnection(url, mysqlUsername, mysqlPassword);
			String sql = "SELECT * FROM t_user WHERE username = '" + username
					+ "' and password = '" + password + "'";
			stmt = con.createStatement();
			rs = stmt.executeQuery(sql);
			return rs.next();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (stmt != null) {
					stmt.close();
				}
				if (con != null) {
					con.close();
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return false;
	}

测试方法:

	@Test
	public void fun() {
		// sql攻击
		String username = "a' or 'a'='a";
		String password = "a' or 'a'='a";
		Boolean bool = login(username, password);
		System.out.println(bool);
	}

结果如下:

图4

结果显示登录成功,但是用户名和密码显示是错误的。其实最终执行的sql是这样的

SELECT * FROM t_user WHERE username = 'a' or 'a'='a' and password = 'a' or 'a'='a'

所以才会返回true。

使用PreparedStatement来防止Sql注入,修改login方法如下:

	public boolean login1(String username, String password) {
		String driverClassName = "com.mysql.jdbc.Driver";
		String url = "jdbc:mysql://localhost:3306/mydb";
		String mysqlUsername = "root";
		String mysqlPassword = "******";
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			Class.forName(driverClassName);
			con = DriverManager
					.getConnection(url, mysqlUsername, mysqlPassword);
			String sql = "SELECT * FROM t_user WHERE username = ? and password = ?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, username);// 为参数赋值
			pstmt.setString(2, password);// 为参数赋值
			rs = pstmt.executeQuery();
			return rs.next();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (pstmt != null) {
					pstmt.close();
				}
				if (con != null) {
					con.close();
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return false;
	}

测试登录方法:

	@Test
	public void fun1() {
		// sql攻击
		String username = "a' or 'a'='a";
		String password = "a' or 'a'='a";
		Boolean bool = login1(username, password);
		System.out.println(bool);
	}

结果如下:

图5

数据库连接池

​ 数据库连接池的基本原理就是为数据库建立一个缓冲池。在缓冲池中先创建指定数量的数据库连接,当有连接请求时就从缓冲池中取出处于“空闲”状态的连接,并将此连接标记为“忙碌”,直到该请求进程结束后,它所使用的连接才会重新回到“空闲”状态,并等待下一次请求调用。
 数据库连接池的主要作用就是负责分配、管理和释放数据库连接,它允许程序重复使用同一个现有的数据库连接,大大缩短了运行时间,提高了执行效率。

数据库连接池的优点

​ 1.资源的高效利用

​ 由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销,减小了系统资源消耗的同时也提高了系统运行环境的平稳性。
​ 2.更快的系统反应速度

​ 数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接可以避免数据库在连接初始化和释放过程所需的时间开销,从而减少了系统的响应时间,提高了系统的反应速度。
​ 3.减少了资源独占的风险

​ 新的资源分配手段对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置实现对某一应用最大可用数据库连接数的限制,避免了应用独占所有数据库资源的风险。
​ 4.统一的连接管理,避免数据库连接泄露

​ 在实现较为完善的数据库连接池时,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。

C3P0的使用
配置文件c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

	<!-- 默认配置 -->
	<default-config>
		<!-- 连接参数配置 -->
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="user">root</property>
		<property name="password">******</property>
		<!--配置数据库连接池的初始连接数、最小链接数、获取连接数、最大连接数、最大空闲时间-->
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">10</property>
		<property name="acquireIncrement">5</property>
		<property name="maxPoolSize">100</property>
		<property name="maxIdleTime">30</property>
	</default-config>

	<!-- 命名配置 -->
	<named-config name="test-config">
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="user">root</property>
		<property name="password">******</property>
		<property name="acquireIncrement">3</property>
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">2</property>
		<property name="maxPoolSize">10</property>
	</named-config>
</c3p0-config>

​ c3p0的配置文件中可以配置多个连接信息,可以给每个配置起个名字,这样可以方便的通过配置名称来切换配置信息。上面文件中默认配置为mysql的配置,名为test-config的配置也是mysql的配置。

Java中得到连接
	/**
	 * 配置文件的默认配置
	 * 
	 * @throws SQLException
	 */
	@Test
	public void fun2() throws SQLException {

		// 创建链接池对象的时候,会自动加载配置文件中的配置。
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		Connection con = dataSource.getConnection();
		System.out.println(con);
		con.close();
	}

	/**
	 * 配置文件中名为test-config的配置
	 * 
	 * @throws SQLException
	 */
	@Test
	public void fun3() throws SQLException {

		// 创建链接池对象的时候,会自动加载配置文件中的配置。
		ComboPooledDataSource dataSource = new ComboPooledDataSource(
				"test-config");// 命名配置
		Connection con = dataSource.getConnection();
		System.out.println(con);
		con.close();
	}
内容概要:本文档系统性地介绍了2024年最新提出的两种智能优化算法——青蒿素优化算法与霜冰优化算法(RIME)的原理、实现方法及其性能对比分析,并提供了完整的Matlab代码实现。文档不仅聚焦于核心算法的仿真与验证,还整合了大量前沿科研资源,涵盖微电网优化、风电功率预测、无人机三维路径规划、电动汽车调度、图像融合、负荷预测、通信信号处理、电力系统故障恢复等多个高价值应用场景。所有案例均基于Matlab/Simulink平台进行建模与仿真,强调算法在复杂工程系统中的实际应用能力,旨在为科研人员提供一套从理论到代码再到应用的完整复现体系。; 适合人群:具备一定编程基础和科研背景的研究生、高校教师及工程技术人员,尤其适合从事智能优化算法研究、新能源系统优化、自动化控制、电力系统调度、无人机导航与路径规划等相关领域的研究人员。; 使用场景及目标:①用于高水平学术论文的复现与创新性研究,提升科研效率与成果产出;②应用于复杂工程系统的建模仿真与智能优化设计,如多能互补系统调度、无人机避障路径规划、微电网能量管理等;③作为智能优化算法的教学与学习资料,深入理解现代元启发式算法的设计思想与实现机制。; 阅读建议:建议读者结合文档中提供的Matlab代码与Simulink仿真模型,按照目录结构循序渐进地学习与实践,优选择与自身研究方向契合的案例进行代码复现,重点关注算法参数设置、收敛曲线分析与多算法对比实验部分,以全面提升算法应用与科研创新能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值