(JDBC-MySql)
概述
JDBC全称Java DataBase Connectivity:java数据库连接
在JDBC创建之前java程序员每操作一款关系型数据库就需要学习java连接该数据库代码,由于关系型数据库过多(如:oracle、db2、MySQL......),不可能全部学习,所以java程序员就期望SUN公司能研发出一套可以运行所有关系型数据库的代码,于是JDBC就出生了。
JDBC其实是SUN公司定义的一套操作所有关系型数据库的接口(规则),具体的实现类则需要数据库公司自行编写,实现类又名为数据库驱动jar包。 当我们使用JDBC编程时实际运行的为数据库驱动jar包中的代码。
使用步骤(mysql为例)
本文所有资源都可到百度云下载 链接:https://pan.baidu.com/s/1J3888hIwUf8qHnKnfFxO6w. 提取码:j1x3
导入驱动jar包
需要到数据库官网下载jar包
-
将jar包复制到IDEA的LIB目录下(此目录可自定义名称)
-
右击jar包点击添加为库(Add as library)
-
Level选择Module Library
-
添加成功后jar包会出现一个下拉箭头,可查看源码
注册驱动
告诉程序该执行指定的jar包程序
三种注册方法
- 反射
//抛出一个ClassNotFoundException异常
Class.forName("com.mysql.jdbc.Driver");
- DriverManager.registerDriver(new Driver()); 第一种反射的com.mysql.jdbc.Driver的源码实际调用了DriverManager类registerDriver静态方法
public class Driver extends NonRegisteringDriver implements java.sql.Driver {js
public Driver() throws SQLException {}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
==注销驱动==
Driver driver = new Driver();//驱动
DriverManager.registerDriver(driver);//注册驱动
DriverManager.deregisterDriver(driver);//注销驱动
注意:Driver的导包为com.mysql.jdbc.Driver中的实现类;而不是java.sql.Driver的接口
- 设置系统属性
System.setProperty("jdbc:drivers","com.mysql.jdbc.Drive");
==注销驱动==
System.clearProperty("jdbc:drivers");//删除系统属性
注意:在mysql5之后可省略注册驱动
因为程序会先读取java.sql.Driver文件注册驱动
获取数据库连接对象Connection
getConnection()存在多个重载方法
-
getConnection(String url) url:数据库网址 ==当数据库没有账号密码时方可使用==
-
getConnection(String url, Properties info) info:作为连接参数的任意键/值对的列表; 通常至少应包含“用户”和“密码”属性
Properties pro = new Properties();
pro.load(Statement01.class.getClassLoader().getResourceAsStream("jdbc.properties"));
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", pro);
- getConnection(String url, String user, String password) user:连接的数据库用户 password:用户密码
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db?characterEncoding=utf8");
url语法:协议名:子协议://服务器名或 IP 地址:端口号/数据库名?参数=参数值
- 如mysql:jdbc:mysql://localhost:3306/数据库[?参数名=参数值]
- 如果访问本机上的mysql服务器且默认端口没有修改,url可简写为: jdbc:mysql:///数据库名[?参数名=参数值]
- 乱码处理:指定编码参数 ?characterEncoding=utf8
执行sql语句
- Statement 用于执行静态SQL语句并返回其生成的结果的对象
Statement statement = connection.createStatement();
Statement对象执行sql的方法
- boolean execute(String sql):执行任意的SQL语句 返回: true-结果是一个ResultSet对象 false-更新计数或没有结果
statement.execute("select * from a");//true
statement.execute("update a set age=20 where id=200");//false
-
int executeUpdate(String sql):执行DML(INSERT,UPDATE,DELETE)给定的SQL语句 返回:sql操作数据影响行
-
ResultSet executeQuery(String sql):执行DQL(SELECT)给定的SQL语句 返回:ResultSet对象,包含给定查询产生的数据
【注意】此对象执行SQL存在SQL注入漏洞:在拼接sql时,存在一些特殊关键字(1=1..)参与时会存在安全问题
String sql = "select * from user where username='"+username+"' and password='"+password+"'";
- username为任意值,
password="' or '1'='1"
时SQL将变为:"select * from user where username='任意值' and password='' or '1'='1'"
便可轻松通过账号密码验证,存在较大隐患
- PreparedStatement
特点:
- 将 SQL 语句发送给数据库预编译,提高 SQL 的执行效率
- SQL参数可使用占位符(?)替代
- 避免sql注入攻击:
String sql="select * from user where username=? and password=?";
PreparedStatement prepar = connection.prepareStatement(sql);
提供参数:void setXXX(int parameterIndex, XXX value)
- parameterIndex:代表sql语句的第几个占位符(?),从1开始计算
- XXX:代表数据类型,如String,int...
PreparedStatement对象执行sql的方法
-
boolean execute():执行任意的SQL语句 返回: true-结果是一个ResultSet对象 false-更新计数或没有结果
-
int executeUpdate():执行DML(INSERT,UPDATE,DELETE)给定的SQL语句 返回:sql操作数据影响行
-
ResultSet executeQuery():执行DQL(SELECT)给定的SQL语句 返回:ResultSet对象,包含给定查询产生的数据
PreparedStatement和Statement的区别
- Statement存在sql注入漏洞,PreparedStatement则不存在
- PreparedStatement编程更易懂,且维护性更好
- Statement没执行一次就需要编译一次sql语句,PreparedStatement只需预编译一次sql语句,之后重复使用时不用再次编译
- 在无需传参不存在sql注入漏洞且只执行一次sql语句时,建议使用Statement,速率较快
- 在需要传参存在sql注入漏洞或一条sql语句需要重复执行时,建议使用PreparedStatement,因为PreparedStatement是通过数据库服务器预编译的,在第一次编译比Statement的时间更长
处理结果
DML操作的结果为int,操作影响数据的行数, DQL操作则返回ResultSet集合
ResultSet 存储查询得到的数据 类似于Enumeration集合
ResultSet resultSet = prepar.executeQuery();
while (resultSet.next()){
resultSet.getInt(1);
resultSet.getInt("age");
}
boolean next() 将光标从当前位置向前移动一行 返回:
- true-新的当前行
- false-没有更多的行
getXXX(int columnIndex) getXXX(String columnLabel)
- XXX:获取参数的数据类型
- columnIndex:代表获取当前行的第几列数据,从1开始计数
- columnLabel:获取当前行列名为columnLabel的数据
释放资源
先开的后关,后开的先关 Connection资源最先打开,最后改变,ResultSet资源最后打开,最先关闭
finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
关闭资源的代码建议放在finally中,避免代码中途出错,导致资源未被关闭,从而占用内存空间
JDBC工具类
每创建一个操作数据库的类就要连接数据库,关闭数据库等一堆冗余的代码,我们可以将重复的代码提取出来作为工具类
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* @program: JDBC
* @description: JDBC工具类
* @author: 吐鲁番
* @Date: 2020/8/21
* @Time: 17:29
**/
public class JDBCutils {
private static Properties pro = null;
static {
try {
//mysql数据库连接的配置文件
pro = new Properties();
//获取配置文件
pro.load(JDBCutils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @Description 获取连接数据库对象
* @return java.sql.Connection
**/
public static Connection getConnection() throws SQLException {
String database = pro.getProperty("database");
return DriverManager.getConnection("jdbc:mysql://localhost:3306/" + database, pro);
}
/**
* @Description 关闭数据库连接对象
**/
public static void closeConnection(Connection con) {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* @Description 关闭执行数据库Statement对象
**/
public static void closeStatement(Statement sta) {
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* @Description 关闭执行数据库PreparedStatement对象
**/
public static void closePreparedStatement(PreparedStatement prepar) {
if (prepar != null) {
try {
prepar.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* @Description 关闭数据对象
**/
public static void closeResultSet(ResultSet res) {
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection con, Statement sta, ResultSet res) {
closeConnection(con);
closeStatement(sta);
closeResultSet(res);
}
public static void close(Connection con, Statement sta) {
close(con, sta, null);
}
public static void close(Connection con, PreparedStatement prepar, ResultSet res) {
closeConnection(con);
closeStatement(prepar);
closeResultSet(res);
}
public static void close(Connection con, PreparedStatement prepar) {
close(con, prepar, null);
}
}
==第一次尝试编写,本着学习的态度,自己可以总结学过的知识,也可以分享给别人==
标签:不准,mysql,数据库,flaot,Driver,PreparedStatement,sql,close From: https://blog.51cto.com/u_14280332/12109109