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

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语句所影响的行数

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

登录方法
/**
* 登录 使用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);
}
结果如下:

结果显示登录成功,但是用户名和密码显示是错误的。其实最终执行的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);
}
结果如下:

数据库连接池
数据库连接池的基本原理就是为数据库建立一个缓冲池。在缓冲池中先创建指定数量的数据库连接,当有连接请求时就从缓冲池中取出处于“空闲”状态的连接,并将此连接标记为“忙碌”,直到该请求进程结束后,它所使用的连接才会重新回到“空闲”状态,并等待下一次请求调用。
数据库连接池的主要作用就是负责分配、管理和释放数据库连接,它允许程序重复使用同一个现有的数据库连接,大大缩短了运行时间,提高了执行效率。
数据库连接池的优点
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();
}
本文深入探讨了JDBC的工作原理及其在Java中如何实现数据库连接。详细介绍了JDBC的结构,包括DriverManager、Connection、Statement和ResultSet等核心组件的作用。此外,还讲解了PreparedStatement的使用,以增强代码的可读性、效率和安全性,有效防止SQL注入。最后,文章讨论了数据库连接池的重要性,特别是在提高资源利用效率和系统响应速度方面的作用。

1502

被折叠的 条评论
为什么被折叠?



