一、JDBC基本知识
是什么
- 英文全称:Java DataBase Connectivity(java语言连接数据库)
- 是sun公司制定一套规范,一套接口
为什么要有JDBC(接口)
- 因为每一个数据库的底层实现原理不一样,恰恰符合面向接口编程,下面解释
JDBC接口的调用者与实现者
- 调用者:java程序员,调用这个接口就可以连接数据库并进行操作,而不管连接的是哪一个数据库
- 实现者:各大数据库厂家,如:MySQL,SQL Sever,Oracle等等,该公司的程序员编写程序实现JDBC接口
一图搞懂JDBC接口
驱动:各大数据库厂家实现JDBC接口的实现类也叫驱动,也就是jar包,需要java程序员到官网上下载二、java中与JDBC相关的接口
相关的接口与类位于java.sql包下,
java与数据库的连接与操作靠这几个接口(类)就可以实现,并且调用前一个接口的方法可以生成,下一个类的对象,是层层递进的关系
三、JDBC编程的步骤
1.步骤总览
2.重点说下前三步
后三步的代码背后没有多少内容,所以先暂时放放
2.1注册驱动
- 告诉java程序,即将要连接的是哪个品牌的数据库
导入MySQL的jar包(驱动)右击项目---->Open Module Settings
找到jar包点击ok即可
代码注册驱动
/**
* @author Think-Coder
* @data 2020/5/5 15:11
*/
import java.sql.*;
public class JDBCTest03
{
public static void main(String[] args){
try{
//1.注册驱动常用方式
//为什么常用:因为参数是一个字符串,字符串可以写道xxx.properties文件中
Class.forName("com.mysql.jdbc.Driver");
}catch(Exception e){
e.printStackTrace();
}
}
}
com.mysql.jdbc.Driver类源码
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {}
static {
try {
//这个方法是注册MySQL驱动的
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
整个注册驱动方法驱动在static静态代码块中,当执行Class.forName(“com.mysql.jdbc.Driver”);时会加载com.mysql.jdbc.Driver类,此时static静态代码块执行,便会注册驱动了
2.2.获取Connection连接:DriverManager.getConnection方法
- 表示JVM的进程和数据库进程之间的通道打开了
- 进程通信,重量级的,使用完一定要关闭
方法参数需要提供
url(统一资源定位符)
如:jdbc:mysql://127.0.0.1:3306/selfproj
jdbc:mysql:// 协议
127.0.0.1 IP地址
3306 端口号
selfproj 数据库名
账号:root
密码:123456代码如下:
代码如下:
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?characterEncoding=utf8","root","123456");
getConnection方法中是三个字符串参数,可以放在外部配置文件中
当更改数据库时,只要更改外部配置文件就搞定,不需要重新启动服务,这个很重要
咱们记住一条规律
只要参数是字符串,用户需要动态变化的,都可以写在外部配置文件中
2.3.获取数据库操作对象:通过Connection接口中的方法创建对象
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
//3.获取数据库操作对象
stmt = conn.createStatement();
//4.执行sql
//存在sql注入问题
//假如此时userName="张三",userPwd="张三'or'1'='1"
//通过字符串拼接将sql关键字or拼接进去
//String sql="select * from user where name='张三' and pwd ='张三'or'1'='1'"
//不需要正确的用户名及密码就能此时就能进入系统
String sql = "select * from user where name='" userName "'and pwd ='" userPwd "'";
//以上正好完成了sql语句的拼接
//以下代码的含义是,发送sql语句给DBMS,DBMS进行sql编译
rs = stmt.executeQuery(sql);
if(rs.next()){
loginSucess = true;
}
}catch (Exception e) {
e.printStackTrace();
}
因为存在SQL注入问题,平时开发基本不用Statement对象,所以没有贴完整得代码
3.JDBC完整的6步
接下来会写一个用户登录完整的代码将JDBC的6步完全融合进去,使用了PreparedStatement对象,操作数据库,是开发中最常用的
public class JDBCTest08 {
public static void main(String[] args) {
//初始化一个界面
Map<String,String> userLoginInfo = initUI();
//验证用户名和密码
boolean loginSucess = false;
try {
loginSucess = login(userLoginInfo);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(loginSucess?"登录成功":"登录失败");
}
//用户登录的方法
public static boolean login(Map<String,String> userLoginInfo){
//打标记
boolean loginSucess = false;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
//单独定义变量
String userName = userLoginInfo.get("loginName");
String userPwd = userLoginInfo.get("loginPwd");
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "123456");
//3.获取数据库预编译PreparedStatement对象
//sql语句框子,一个?代表一个占位符
String sql = "select * from test where id=? and pwd=?";
//程序执行到此,会发送sql语句框子给DBMS,然后DBMS进行sql语句的预先编译
//此时sql语句中没有用户输入的值,很好的解决了sql注入问题
ps = conn.prepareStatement(sql);
//给?占位符传值
ps.setString(1, userName);
ps.setString(2, userPwd);
//4.执行sql
rs = ps.executeQuery();
//5.处理返回的结果集
// rs为返回的结果集
if (rs.next()) {
loginSucess = true;
}
}catch (Exception e){
e.printStackTrace();
} finally {
//6.释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSucess;
}
//用户输入的方法
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.println("用户名:");
String loginName = s.nextLine();
System.out.println("密码:");
String loginPwd = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
return userLoginInfo;
}
}
解释说明
完整的JDBC编程6步就写完了,JDBC编程6步是针对于查询的
对于增删改的,是不需要第5步的,因为没有返回查询结果集
使用增删改时,只需将第4步ps.executeQuery()变为ps.executeUpdate()就可以了,代码我就不写了,哈哈
下面对比Statement对象和PreparedStatement对象
1.Statement存在sql注入问题,PreparedStatement解决了sql注入问题。
2.PreparedStatement执行效率高,编译一次执行多次,因为相同的sql语句不会再编译
而Statement编译一次执行一次,因为基本上sql语句不会相同
3.PreparedStatement会在编译阶段做类型检查
总结:开发场景中99%使用PreparedStatement对象,在需要SQL注入的业务场景中使用Statement
四.封装工具类
注册驱动、连接数据库和释放连接经常使用可以封装到工具类中
public class DBUtil {
/*
* 工具类中的构造方法都是私有的
* 因为工具类当中的方法是静态的,不需要new对象,直接采用类名调用
* */
private DBUtil(){}
//静态代码块在类加载时执行,并且只执行一次
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/*
* 获取数据库连接对象
* */
public static Connection getConnection()throws Exception{
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
}
/*
* 关闭资源
* */
public static void close(Connection conn, Statement ps, ResultSet rs){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用工具类,实现模糊查询
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//使用工具类获取连接
conn=DBUtil.getConnection();
//获取预编译的数据库操作对象
String sql = "select * from user where pwd like ?";
ps = conn.prepareStatement(sql);
//实现查询密码第二位是2的
ps.setString(1,"_2%");
rs=ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("pwd"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//使用工具类释放资源
DBUtil.close(conn,ps,rs);
}
}
五、总结
JDBC是一套让各个数据库厂家实现的接口,通过调用这些接口,实现java程序连接数据库,很好体现面向接口编程的特点