核心API
注册驱动
Class.forName(“com.mysql.cj.jdbc.Driver”); 在Java中,当使用JDBC连接数据库时,需要加载数据库特定的驱动程序,以便与数据库进行通信,加载驱动程序的目的是为了注册驱动程序,使得JDBC API能够识别并与特定的数据库进行交互 从JDK6开始,不需要显式地调用Class.forName()来加载JDBC驱动程序,只要在路径中集成了对应的jar文件,会自动在初始化时注册驱动程序。
Connection
Connection接口是JDBC API的重要接口,用于建立与数据库的通信通道,Connection对象不为空,则代表一交数据库连接 在建立连接时,需要指定数据库URL、用户名、密码参数
URL:jdbc:mysql://192.168.29.201:3306/jdbc URL:jdbc:mysql://IP地址:端口号/数据库名?参数键值对1&参数键值对2 Connection接口还负责管理事务,Connection接口提供了commit和rollback方法,用于事务提交和回滚 在使用JDBC技术时,必须先获取Connection对象,使用完毕后,要释放资源,避免资源占用造成泄露
Statement
Statement接口用于执行SQL语句并与数据库进行交互,它是JDBC API一个重要接口,通过Statement对象,可以向数据库发送SQL语句并获取执行结果 结果可以是一个或多个结果
增删改:受影响行数单个结果 查询:单行单列,多行多列,单行多列等结果 Statement接口在执行SQL语句时,会产生SQL注入攻击问题
不使用Statement执行动态构建的SQL查询时,往往需要将查询条件与SQL语句拼接在一起,直接将参数和SQL语句一并生成,让SQL的查询条件始终为true得到结果
public class JDBCInjection {
public static void main ( String [ ] args) throws SQLException {
String url = "jdbc:mysql://192.168.29.201:3306/jdbc" ;
String username = "root" ;
String password = "Lotus!1120" ;
Connection conn = DriverManager . getConnection ( url, username, password) ;
Statement statement = conn. createStatement ( ) ;
System . out. println ( "Please input your emp_name:" ) ;
Scanner scanner = new Scanner ( System . in) ;
String name = scanner. nextLine ( ) ;
String statement_sql = "select * from jdbc.t_emp where emp_name='" + name + "'" ;
System . out. println ( statement_sql) ;
ResultSet rs = statement. executeQuery ( statement_sql) ;
while ( rs. next ( ) ) {
int emp_id = rs. getInt ( "emp_id" ) ;
String emp_name = rs. getString ( "emp_name" ) ;
double emp_salary = rs. getDouble ( "emp_salary" ) ;
int emp_age = rs. getInt ( "emp_age" ) ;
System . out. println ( emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age) ;
}
rs. close ( ) ;
statement. close ( ) ;
conn. close ( ) ;
}
Please input your emp_name:
abc' or ' 1 '=' 1
select * from jdbc. t_emp where emp_name= 'abc' or '1' = '1'
1 edison 777.77 23
2 dizzy 888.88 24
3 tye 999.99 25
4 water 333.33 27
PreparedStatement
PreparedStatement是Statement接口的子接口,用于执行预编译的SQL查询,作用如下
预编译SQL语句:在创建PreparedStatement时,会预编译SQL语句,也就是SQL语句已经固定 防止SQL注入:PreparedStatement支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来,无论传递什么都作为值,有效防止关键字或值导致SQL注入问题 性能提升,PreparedStatement是预编译SQL语句,同一SQL语句多次执行的情况下,可以复用,不必每次重新编译和解析 更安全和高效
public class JDBCPreparedStatement {
public static void main ( String [ ] args) throws SQLException {
String url = "jdbc:mysql://192.168.29.201:3306/jdbc" ;
String username = "root" ;
String password = "Lotus!1120" ;
Connection conn = DriverManager . getConnection ( url, username, password) ;
String statement_sql = "select * from jdbc.t_emp where emp_name=?" ;
PreparedStatement statement = conn. prepareStatement ( statement_sql) ;
System . out. println ( "Please input your emp_name:" ) ;
Scanner scanner = new Scanner ( System . in) ;
String name = scanner. nextLine ( ) ;
statement. setString ( 1 , name) ;
ResultSet rs = statement. executeQuery ( ) ;
while ( rs. next ( ) ) {
int emp_id = rs. getInt ( "emp_id" ) ;
String emp_name = rs. getString ( "emp_name" ) ;
double emp_salary = rs. getDouble ( "emp_salary" ) ;
int emp_age = rs. getInt ( "emp_age" ) ;
System . out. println ( emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age) ;
}
rs. close ( ) ;
statement. close ( ) ;
conn. close ( ) ;
}
}
ResultSet
ResultSet是JDBC API中的一个接口,用于表示从数据库中执行查询语句返回的结果集,它提供了一种用于遍历和访问查询结果的方式 遍历结果:ResultSet可以使用next()方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为boolean类型,true代表有下一行结果,false代表没有 获取单列结果:可以通过getXXX方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取
package com. lotus. base ;
import org. junit. After ;
import org. junit. Before ;
import org. junit. Test ;
import java. sql. * ;
public class JDBCOperation {
private Connection conn;
private PreparedStatement statement;
private ResultSet rs;
@Before
public void init ( ) throws SQLException {
String url = "jdbc:mysql://192.168.29.201:3306/jdbc" ;
String username = "root" ;
String password = "Lotus!1120" ;
conn = DriverManager . getConnection ( url, username, password) ;
}
@Test
public void testQuerySingleRowAndColumn ( ) throws SQLException {
String statement_sql = "select count(*) as count from jdbc.t_emp" ;
statement = conn. prepareStatement ( statement_sql) ;
rs = statement. executeQuery ( ) ;
while ( rs. next ( ) ) {
System . out. println ( rs. getInt ( 1 ) ) ;
System . out. println ( rs. getInt ( "count" ) ) ;
}
}
@Test
public void testQuerySingleRowAndMultiCol ( ) throws SQLException {
String statement_sql = "select * from jdbc.t_emp where emp_id=?" ;
statement = conn. prepareStatement ( statement_sql) ;
statement. setInt ( 1 , 2 ) ;
rs = statement. executeQuery ( ) ;
while ( rs. next ( ) ) {
int emp_id = rs. getInt ( "emp_id" ) ;
String emp_name = rs. getString ( "emp_name" ) ;
double emp_salary = rs. getDouble ( "emp_salary" ) ;
int emp_age = rs. getInt ( "emp_age" ) ;
System . out. println ( emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age) ;
}
}
@Test
public void testQueryMultiRowAndMultiCol ( ) throws SQLException {
String statement_sql = "select * from jdbc.t_emp where emp_age>?" ;
statement = conn. prepareStatement ( statement_sql) ;
statement. setInt ( 1 , 23 ) ;
rs = statement. executeQuery ( ) ;
while ( rs. next ( ) ) {
int emp_id = rs. getInt ( "emp_id" ) ;
String emp_name = rs. getString ( "emp_name" ) ;
double emp_salary = rs. getDouble ( "emp_salary" ) ;
int emp_age = rs. getInt ( "emp_age" ) ;
System . out. println ( emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age) ;
}
}
@Test
public void testInsert ( ) throws SQLException {
String statement_sql = "insert into t_emp(emp_name,emp_salary,emp_age) values (?,?,?)" ;
statement = conn. prepareStatement ( statement_sql) ;
statement. setString ( 1 , "rose" ) ;
statement. setDouble ( 2 , 111.11 ) ;
statement. setInt ( 3 , 33 ) ;
int result = statement. executeUpdate ( ) ;
if ( result > 0 ) {
System . out. println ( "Success" ) ;
} else {
System . out. println ( "Failure" ) ;
}
}
@Test
public void testUpdate ( ) throws SQLException {
String statement_sql = "update t_emp set emp_salary = ? where emp_id = ?" ;
statement = conn. prepareStatement ( statement_sql) ;
statement. setDouble ( 1 , 000.11 ) ;
statement. setInt ( 2 , 2 ) ;
int result = statement. executeUpdate ( ) ;
if ( result > 0 ) {
System . out. println ( "Success" ) ;
} else {
System . out. println ( "Failure" ) ;
}
}
@Test
public void testDelete ( ) throws SQLException {
String statement_sql = "delete from t_emp where emp_id = ?" ;
statement = conn. prepareStatement ( statement_sql) ;
statement. setDouble ( 1 , 5 ) ;
int result = statement. executeUpdate ( ) ;
if ( result > 0 ) {
System . out. println ( "Success" ) ;
} else {
System . out. println ( "Failure" ) ;
}
}
@After
public void destory ( ) throws SQLException {
if ( rs != null ) {
rs. close ( ) ;
}
if ( statement != null ) {
statement. close ( ) ;
}
if ( conn != null ) {
conn. close ( ) ;
}
}
}
常见问题
资源管理
在使用JDBC相关资源时,如Connection,PreparedStatement,ResultSet,使用完毕后,要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏
SQL语句问题
java.sql.SQLSyntaxErrorException:SQL语句错误异常,一般有几种情况
SQL语句错误,检查SQL语句!建议SQL语句在SQL工具中测试后再复制到Java程序中 连接数据库的URL中,数据库名称编写错误,也会报该异常
SQL语句未设置参数问题
java.sql.SQLException:No value specified for parameter 1
在使用预编译SQL语句时,如果有?占位符,要为每一个占位符赋值,否则报该错
用户名或密码错误
java.sql.SQLException: Access denied for user ‘root1’@‘192.168.29.1’ (using password: YES)
通信异常
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
在连接数据库的URL中,如果IP或端口写错了,会报上述异常