1. JDBC简介
- JDBC是一套用于执行SQL语句的Java API,应用程序可通过这套API连接到关系型数据库,并使用SQL语句完成对数据库中数据的查询、增删改等操作
- 不同种类的数据库(如MySQL、Oracle等)在内部处理数据的方式是不同的,如果使用数据库厂商提供的访问接口操作数据库,应用程序可移植性就会变得很差。JDBC要求各个数据库厂商按照统一的规范提供数据库驱动,而在程序中由JDBC和具体的数据库驱动联系,所以用户就不必直接与底层的数据库交互,这使得代码的通用性更强。
-
JDBC在应用程序与数据库之间起到了一个桥梁作用,当应用程序使用JDBC访问特定的数据库时,需要通过不同数据库驱动与不同的数据库进行连接,连接后即可对数据库进行相应的操作。
-
使用时需导入的jar包
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> <!--Mysql8.0版本--> <!--<version>5.1.48</version>--> <!--Mysql5.0版本--> </dependency>
2. JDBC的常用API
2.1 Driver接口
- Driver接口是所有JDBC驱动程序必须实现的接口,必须要把所使用的数据库驱动程序或类库加载到项目的classpath中(这里指MySQL驱动JAR包)
2.2 DriverManager(驱动管理类)类
- 用于加载JDBC驱动并且创建与数据库的连接
//向DriverManager中注册给定的JDBC驱动程序
registerDriver(Driver driver)
/*
建立与数据库的连接,并返回表示连接的Connection对象
url:连接路径
jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&...
示例:jdbc:mysql://127.0.0.1:3306/DB1
如果连接的是本机mysql服务器且默认端口是3306,url可以简写成jdbc:mysql:///数据库名称?参数键值对1&...
配置useSSL=false参数,禁用安全连接方式,解决警告提示
user:用户名
password:密码
*/
getConnection(String url, String user, String password)
-
可用以下方法代替registerDriver注册驱动
Class.forName("com.mysql.jdbc.Driver"); //Driver的部分源码 static{ try{ DriverManager.registerDriver(new Driver()); } catch(SQLException var1) { throw new RuntimeException("Can't register driver!"); } }
提示:
- Mysql 5之后的驱动包,可以省略注册驱动的步骤
- 自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
2.3 Connection接口
- 表示Java程序和数据库的连接,只有获得该连接对象后才能访问数据库并操作数据表
//获取表示数据库元数据的DatabaseMetaData对象
DatabaseMetaData getMetaData()
//创建一个Statement对象并将SQL语句发送到数据库
void createStatement()
//创建一个PreparedStatement对象并将参数化的SQL语句发送到数据库
void preparedStatement()
//创建一个CallableStatement对象来调用数据库存储过程
void CallableStatement()
//提交事务,并释放Connection对象当前持有的所有数据库锁,当事务被设置为手动提交时,需要调用该方法提交事务
void commit()
//回滚事务(程序出现异常时需要回滚),其它要点同上
void rollback()
//设置Connection对象的提交模式,自动:true;手动:false
void setAutoCommit(boolean autoCommit)
2.4 Statement接口
- 执行静态的SQL语句,并返回一个结果对象
//执行各种SQL语句,返回一个boolean值,true:表示所执行的SQL语句有查询结果
boolean execute(String sql)
//执行insert\update\delete语句,返回int值,表示数据库中受该语句影响的行数
int executeUpdate(String sql)
//执行select语句,返回表示查询结果的ResultSet对象
ResultSet executeQuery(String sql)
//将sql添加到Statement对象的当前命令列表中,该方法用于SQL命令的批处理
void addBatch(String sql)
//清除Statement对象中的命令列表
void clearBatch()
//将一批sql命令提交给数据库执行,返回更新计数组成的数组
int[] executeBatch()
2.5 PreparedStatement接口
-
执行预编译的语句,扩展了带有参数的SQL语句的执行操作,使用占位符
'?'
代替SQL语句中的参数,然后再对其进行赋值,预防SQL注入问题 -
SQL注入:通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法
//登录案例 String name = "why";//用户名 String pwd = " 'or'1' = '1";//密码 String sql = "select * from users where username=' "+name+" ' and password=' "+pwd"'"; //上述sql语句拼接后为 select * from users where username = 'wht' and password = ''or '1' = '1'; //无论whrer条件是否满足,后面 or '1' = '1'是始终满足的,最终条件是成立的,所以是可以正常登录的 //使用占位符? select * from users where username = 'why' and password = '\'or \'1\' = \'1'
//执行SQL语句,该语句必须是一个DML语句或者无返回内容的SQL语句,例如DDL语句
int executeUpdate()
//执行SQL查询,返回ResultSet对象
ResultSet executeQuery();
/*调用以上两个方法时不需要传递SQL语句,因为获取sql语句执行对象时已经对sql语句进行预编译了*/
//将指定参数设置为给定的X值
void setX(int parameterIndex, X x)
//将一组参数添加到此PreparedStatement对象的批处理命令中
void addBatch()
//将指定的输入流写入数据库的文本字段中
setCharacterStream(int parameterIndex, Reader reader, int length)
//将二进制的输入流写入数据库的二进制字段中
setBinaryStream(int parameterIndex, InputStream x, int length)
-
原理
-
将sql语句发送到MySQL服务器端
-
MySQL服务端会对sql语句进行如下操作
-
检查SQL语句
检查SQL语句的语法是否正确。
-
编译SQL语句。将SQL语句编译成可执行的函数。
检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
-
执行SQL语句
-
-
2.6 ResultSet接口
- 保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中,在ResultSet接口内部有一个指向表格数据行的游标(指针)
//获取指定字段的值,参数columnIndex代表字段的索引,columnName代表字段的名称
String getString(int columnIndex)
String getString(String columnName)
//获取指定字段的值
X getX(int columnIndex)
X getX(String columnName)
//将游标从当前位置向下移一行,新行有效返回true
boolean next()
//将游标移动到ResultSet对象的指定行
boolean absolute(int row)
//将游标移动到ResultSet对象的末尾,即最后一行之后
boolean afterlast()
//将游标移动到ResultSet对象的开头,即第一行之前
boolean beforeFirst()
//将游标从当前位置向上移一行
boolean previous()
//将游标移动到ResultSet对象的最后一行
boolean last()
3. 实现JDBC程序
//1.加载并注册数据库驱动,mysql5是com.mysql.jdbc.Driver
Class.forName("com.mysql.cj.jdbc.Driver");
//2.通过DriverManager获取数据库连接
String url = "jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义sql
String sql = "select * from users";
//4.通过Connection获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//5.使用Statement对象执行sql
ResultSet rs = stmt.executeQuery(sql);
//6.操作ResultSet结果集
...
//7.关闭连接,释放资源
rs.close();
stmt.close();
conn.close();
4. 分页查询
-
两种典型的分页方法
-
通过ResultSet的光标实现分页
- 通过移动的光标,可以设置记录的起始位置和结束位置来实现分页
- 优点:在各种数据库上通用;缺点:占用大量资源,不适合数据量大的情况
-
通过数据库机制进行分页
select 字段列表 from 表面 limit 起始索引, 查询条目数;
- 优点:减少资源开销,提高程序性能;缺点:只针对某一种数据库通用
-