什么是jdbc
JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现,本文中的代码都是针对MySQL数据库实现的
jdbc的工作原理:
jdbc主要由jdbc api、jdbc Driver Manager和jdbc驱动组成。
工作原理如图:
JDBCAPI:是jdbc的武器库,开发者可以使用里面的类与接口实现与数据的连接和操作
如:Connection(连接接口)、Statement接口、ResultSet(结果集)接口PreparedStatement接口等。
JDBC Driver Manager:
是JDBC体系结构的支柱,他负责管理各种JDBC驱动(如MYSQL数据库或Oracle数据库的JDBC驱动等)。 JDBC Driver Manager位于JDK的java.sql包中。
JDBC驱动:
JDBC驱动不包含在JDK要导入相关架包架包如下:
JDBC API:
是Java应用程序与各种数据库交互的标准接口,功能就是建立与数据库的连接,执行sql语句和拿到返回结果。
JDBC的主要类/接口的功能如下:
1)与数据库建立连接
>DriverManager类:装载驱动程式,并且创建新的数据库连接提供支持
>Connection接口:负责连接数据库并承但传输数据的任务.
2)发送sql语句:
>Statement接口:由Connection产生,负责执行sql语句。
>PreparedStatement接口:Statement的子接口,也由Connection产生,同样负责执行Sql语句。
比Statement接口相比具有更高的安全性。性能更高、可读性更高、维护也比较容易
3)放回处理结果
>ResultSet接口:负责保存和处理Statement执行后的查询结果.
使用JDBC连接数据库的方法:
1.加载JDBC驱动
2.与数据库建立连接
3.发送sql语句,并得到放回结果
4.处理放回结果
jdbc访问数据库的步骤
//1.加载驱动
//2.建立连接
//3.创建执行对象
//4.开始执行SQL
//5.处理执行结果
//6.释放资源
使用Class.forName(要先导入架包)
try{Class.forName("JDBC驱动类的名称");}catch(ClassNotFoundException e){//处理异常代码}
使用DriverManager建立连接:
语法如下:
jdbc:数据库(是数据库的款式如:mysql)://ip:端口/数据库名称[?连接参数=参数值];
其中:
>数据库是:JDBC连接的目标数据库,如mysql数据库
>ip:JDBC所连接的目标数据库地址,如果是本地数据库,则可以是localhost
>端口:连接数据库的端口号,如果连接的是MySQL则是3306
>数据库名称:则是目标数据库的名称如hospital
>连接参数:时区
jdbc:mysql://localhost:3306/hospital?serverTimezone=GMT-8
Connection是数据库连接对象的类型
常用方法
| 方法 | 作用 |
|---|---|
| Statement createStatement() | 创建一个Statement对象将SQL语句发送到数据库 |
| PreparedStatement prepareStatement(String sql) | 创建一个PreparedStatement对象,将参数化的SQL语句发送到数据库 |
| boolean isClosed() | 查询此Connection对象是否已经被关闭。如果已关闭,则返回true;否则返回false |
| void close() | 立即释放此Connection对象的数据库和JDBC资源 |
关键代码模块:
常见错误:
使用JDBC连接数据库时,经常出现的错误
JDBC驱动类的名称书写错误,导致ClassNotFoundException异常
数据连接字符串、数据库用户名、密码错误,导致SQLException异常
数据库操作结束后,没有关闭数据库连接,导致仍旧占有系统资源
关闭数据库连接语句没有放到finally语句块中,导致语句可能没有被执行
Statement接口:
Java执行数据库操作的一个重要接口
在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句
分类
Statement对象:执行不带参数的简单SQL语句
PreparedStatement对象:执行带或不带In参数的预编译SQL语句
常用方法
| 方法 | 作用 |
|---|---|
| ResultSet executeQuery(String sql) | 可以执行SQL查询并获取ResultSet对象 |
| int executeUpdate(String sql) | 可以执行插入、删除、更新的操作,返回值是执行该操作所影响的行数 |
| boolean execute(String sql) | 可以执行任意SQL语句。如果结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回false |
出String类和StringBuffer类的共同点和不同点
String类
字符串常量一旦声明则不可改变
String类对象可以改变,但改变的是其内存地址的指向
使用“+”作为数据的连接操作
不适用频繁修改的字符串操作
StringBuffer类
StringBuffer类对象能够被多次修改,且不产生新的未使用对象
使用append()方法进行数据连接
适用于字符串修改操作
是线程安全的,支持并发操作,适合多线程
如果使用StringBuffer生成了String类型字符串,可以通过toString( )方法将其转换为一个String对象
使用Statement接口执行插入数据的操作的方法
executeUpdate()方法
execute()方法
如果希望得到插入成功的数据行数,可以使用executeUpdate()方法;否则,使用execute()方法
实现步骤
声明Statement变量
创建Statement对象
构造SQL语句
执行数据插入操作
关闭Statement对象
使用PreparedStatement接口操作数据库
为什么使用PreparedStatement:
可以避免sql注入攻击
sql注入攻击:
通过提交一段SQL代码,执行超出用户访问权限的数据操作称为SQL注入(SQL Injection)
SQL注入攻击是应用安全领域的一种常见攻击方式,会造成的数据库安全风险包括:刷库、拖库和撞库等
主要是没有对用户输入数据的合法性进行判断,导致应用程序存在安全隐患
PreparedStatement常用方法:
| 方 法 | 作 用 |
|---|---|
| boolean execute() | 执行SQL语句,可以是任何SQL语句。如果结果是Result对象,则返回true。如果结果是更新计数或没有结果,则返回false |
| ResultSet executeQuery() | 执行SQL查询,返回该查询生成的ResultSet对象 |
| int executeUpdate() | 执行SQL语句,该语句必须是一个DML语句,比如:INSERT、UPDATE或DELETE语句;或者是无返回内容的SQL语句,比如DDL语句。返回值是执行该操作所影响的行数 |
| void setXxx(int index,xxx x) | 方法名Xxx和第二个参数的xxx均表示(如int,float,double等)基本数据类型,且两个类型需一致,参数列表中的x表示方法的形式参数。 把指定数据类型(xxx)的值x设置给index位置的参数。根据参数类型的不同,常见方法有: setInt(int index,int x) 、setFloat(int index,float x)、 setDouble(int index,double x)等 |
| void setObject(int index,Object x) | 除基本数据类型外,参数类型也可以是Object,可以将Object对象x设置给index位置的参数 |
与Statement接口相比,具有的优势
可读性和可维护性高
SQL语句执行性能高
安全性更高
jdbc连接数据库查询的案例:
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import java.sql.*;public class HospitalQuery {private static Logger logger = LogManager.getLogger(HospitalQuery.class.getName());public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs=null;//1.记载驱动try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}try {//2.建立连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=GMT-8&useUnicode=true&characterEncoding=utf-8", "cty", "cty");//3.常见Statementstmt = conn.createStatement();//构造sqlString sql="select patientID,patientName,gender,address from patient limit 3;";//执行查询操作rs=stmt.executeQuery(sql);//移动光标遍历结果while(rs.next()){ System.out.println(rs.getInt("patientID")+"\t"+rs.getString("patientName")+"\t"+rs.getString("gender")+"\t"+rs.getString("address"));}} catch (SQLException e) {logger.error(e);} finally {try {if(null!=rs){rs.close();}if (null != stmt) {stmt.close();}if (null != conn) {conn.close();System.out.println("连接断开");}} catch (SQLException e) {logger.error(e);}}}
public class HospitalInsert {private static Logger logger= LogManager.getLogger(HospitalInsert.class.getName()); public static void main(String[] args) {Connection conn=null; Statement stmt=null;String name="张菲";String gender="女";String birthDate="1995-02-12";String phoneNum="13887676500";String email="fei.zhang@qq.com";String passWord="909000";String identityNum="610000199502126100";String address="北京市";//1.加载驱动try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error(e);}//2.建立连接try {conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/hospital?serverTimezone=GMT-8&useUnicode=true&characterEncoding=utf-8","cty","cty");//创建Statement对象stmt=conn.createStatement();//构造sqlStringBuffer sbSql=new StringBuffer("insert into patient(password,birthDate,patientName,"+"phoneNum,email,identityNum,address)"+ "VALUES('");sbSql.append(passWord+"','");sbSql.append(birthDate+"','");sbSql.append(name+"','");sbSql.append(phoneNum+"','");sbSql.append(email+"','");sbSql.append(identityNum+"','");sbSql.append(address+"');");System.out.println(sbSql.toString());stmt.execute(sbSql.toString());} catch (SQLException e) {logger.error(e);}finally{try {if(null!=stmt){stmt.close();}if(null!=conn){conn.close();}} catch (SQLException e) {logger.error(e);}}}
public class demo3 {public static void main(String[] args) {Scanner in=new Scanner(System.in);Connection con = null; PreparedStatement stmt=null; ResultSet rs=null;try {Class.forName("com.mysql.jdbc.Driver");con = DriverManager.getConnection("jdbc:mysql://localhost:3306/paycorp?serverTimezone=GMT-8&useUnicode=true&characterEncoding=utf-8", "cty", "cty");System.out.println("连接成功");String sql="select * from account where accountName=? and pwd=?"; System.out.println("请输入用户名:");String name=in.next();System.out.println("请输入密码:");String pwd=in.next();stmt=con.prepareStatement(sql);stmt.setString(1,name);stmt.setString(2,pwd);rs=stmt.executeQuery();if(rs.next()){System.out.println("成功");}else{ System.out.println("失败");}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}finally{try {if(null!=rs){rs.close();}if(null!=stmt){stmt.close();}if(null!=con){con.close();}} catch (SQLException throwables) {throwables.printStackTrace();}}}
&useUnicode=true&characterEncoding=utf-8”加上这段代码可以解决输入插入到数据库时乱码的问题
JDBC详细讲解链接:
https://blog.csdn.net/Jungle_Rao/article/details/81274720?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163762739316780264092527%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163762739316780264092527&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-81274720.first_rank_v2_pc_rank_v29&utm_term=jdbc&spm=1018.2226.3001.4187
Statement和PreparedStatement的异同及优缺点
同:两者都是用来执SQL语句的
异:PreparedStatement需要根据SQL语句来创建,它能够通过设置参数,指定相应的值,不是像Statement那样使用字符串拼接的方式。
PreparedStatement的优点:
1、其使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差。
2、其具有预编译机制,性能比statement更快。
3、其能够有效防止SQL注入攻击。
execute和executeUpdate的区别
相同点:二者都能够执行增加、删除、修改等操作。
不同点:
1、execute可以执行查询语句,然后通过getResult把结果取出来。executeUpdate不能执行查询语句。
2、execute返回Boolean类型,true表示执行的是查询语句,false表示执行的insert、delete、update等。executeUpdate的返回值是int,表示有多少条数据受到了影响。
//1.加载驱动
//2.建立连接
//3.创建执行对象
//4.开始执行SQL
//5.处理执行结果
//6.释放资源
