JDBC,全称Java Database Connectivity
提供一种与平台无关的,用于执行sql语句的标准API,可以方便的实现多种关系型数据库的统一操作,由一组用Java语言编写的类和接口组成。
厂商只要实现JDBC接口就能使用JDBC执行Java操作,可移植性强
JDBC分为以下四种
1.DriverManager 用于管理JDBC驱动程序
2.Connection 用于建立特定数据库的连接,一个连接就是一个会话,建立连接之后,可以执行sql语句,获取检索结果
3.Statement 一个statement对象用于执行静态sql,并且获得语句执行后的结果
4.Preparedstatement 创建一个可以编译的sql语句对象,该对象可以被多次运行,用来提高执行的效率,Statement的子接口
5.Resultset 用于创建表示sql语句结果的结果集,用户可以通过结果集完成对数据库的访问
6.Callablestatement 用于执行sql的存储过程
7.Driver 定义一个书库驱动程序的接口
Preparedstatement是Statement的子接口
8.Date 该类是标准的Date的一个子集,用于表示sqlDate类型,日期类型 不包含时间
9.Timestamp 标准的Date的一个扩展,用于表示sg1中时间戳,增加了一个关于纳秒时间域
10.Time 该类是标准的Date的一个子集,用于表示sqlTime类型,时间类型 的时分秒
11.DatabaseMetaData再出现数据库异常的时候,报告异常或者警告
12.DataTruncation 跟ReusltSetMetaData一起访问数据库的元信息
13.SOLException 数据库异常
14.SOLWarming 数据库警告
15.DriverPropertyInfo 驱动属性的所有信息
16.Types 常量
1.安装数据库
2.加载数据库的驱动程序 每个数据库的厂商都有不同的数据库驱动程序 mysql
3.让Java连接数据库 连接地址:jdbc:mysgl://localhost:3306/数据库名
4.通过java进行数据库的操作
Statement
PreparedStatement
Callablestatement
5.数据库属于资源类,打开之后,一定需要关闭
写程序的步骤:
新建一个lib包,复制上面在maven下载的驱动jar包,粘贴到lib包内,右击jar包,选择Add as Library
Class.forName("com.mysql.jdbc.Driver");
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, username, password);
括号内三个参数不能写死,要为后续的更改提供便利,在获取连接代码上面写
String url="jdbc:mysql://127.0.0.1:3306/my_db";//自己要连接进行下一步操作的数据库
String username="root";//自己电脑mysql的用户名
String password="1234";//用户名对应的密码
Connection conn = DriverManager.getConnection(url, username, password);
String sql="UPDATE…………";//自行定义操作
Statement stmt=conn.createStatement();
int count = stmt.executeUpdate(sql);//受影响的行数
简易案例
package com.svt.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC的快速入门
*/
public class JDBCDemo {
//public static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
public static void main(String[] args) throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//5.16之后省略注册
//2.获取连接
String url="jdbc:mysql://127.0.0.1:3306/my_db";
String username="root";//自己电脑mysql的用户名
String password="1234";//用户名对应的密码
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="UPDATE account SET money = 2000 WHERE id=1";
//4.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
作用
1、注册驱动
2、获取数据库连接
举例
package com.svt.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo2_DriverManager {
//public static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
public static void main(String[] args) throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";//自己电脑mysql的用户名
String password="1234";//用户名对应的密码
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="UPDATE account SET money = 2000 WHERE id=1";
//4.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
package com.svt.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo3_Connection {
//public static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
public static void main(String[] args) throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql1="UPDATE account SET money = 3000 WHERE id=1";
String sql2="UPDATE account SET money = 3000 WHERE id=2";
//4.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
try {
//开启事务
conn.setAutoCommit(false);
//5.执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6.处理结果
System.out.println(count1);
//int i = 3/0;
//5.执行sql
int count2 = stmt.executeUpdate(sql2);//受影响的行数
//6.处理结果
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception e) {
//回滚事务
conn.rollback();
e.printStackTrace();
}
//7.释放资源
stmt.close();
conn.close();
}
}
作用
执行SQL语句
int executeUpdate(sql): 执行DML、DDL语句
返回值: (1)DML语句影响的行数(2)DDL语句执行后,执行成功也可能返回 0
ResultSet executeQuery(sql): 执行DQL语句
返回值: ResultSet 结果集对象
举例-使用Test单元测试来分块测试,需要导包,可以写@Test,然后alt+回车自动导入
package com.svt.jdbc;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo4_Statement {
/**
* 执行DML语句
* @throws Exception
*/
@Test//要导包
public void testDML() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="UPDATE account SET money = 4000 WHERE id=2";
//4.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句后 受影响的行数
//6.处理结果
//System.out.println(count);
if (count>0){
System.out.println("修改成功!");
}else {
System.out.println("修改失败!");
}
//7.释放资源
stmt.close();
conn.close();
}
/**
* 执行DDL语句
* @throws Exception
*/
@Test//要导包
public void testDDL() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="drop database db1";
//4.获取执行sql的对象 Statement
Statement stmt=conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DDL语句后 可能返回0
//6.处理结果
//System.out.println(count);
/*if (count>0){
System.out.println("修改成功!");
}else {
System.out.println("修改失败!");
}*/
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
package com.svt.jdbc;
import com.svt.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class JDBCDemo5_ResultSet {
@Test//要导包
public void testResultSet() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="select * from account";
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//6.处理结果,遍历rs中的所有数据
//6.1光标向下移动一行,并且判断当前行是否有数据
/*while (rs.next()){
//6.2获取数据 getXxx()
int id=rs.getInt(1);
String name = rs.getString(2);
double money = rs.getDouble(3);
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------------");
}*/
while (rs.next()){
//6.2获取数据 getXxx()
int id=rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------------");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
@Test//要导包
public void testResultSet2() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3.定义SQL语句
String sql="select * from account";
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//创建集合
List<Account> list = new ArrayList<>();
//6.处理结果,遍历rs中的所有数据
//6.1光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
Account account = new Account();
//6.2获取数据 getXxx()
int id=rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//赋值
account.setId(id);
account.setName(name);
account.setMoney(money);
//存入集合
list.add(account);
}
//查看结果 打印数据
System.out.println(list);
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
String pwd=“’ or’1’='1”;
String sql=“SELECT * FROM tb_user where username='”+name+“‘and password=’”+pwd+“'”;
这样写会导致输出结果为 select * from tb_user where username = '...' and password = '' or '1'='1';
username = '...'
返回true,password = ''
->空字符串,返回false,而'1'='1'
永远返回true,此时where就面临选择false or true,条件就为true,所以无论你输入什么密码都能进入数据库进行修改,这就是SQL注入
package com.svt.jdbc;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 用户登录
*/
public class JDBCDemo6_UserLogin {
@Test//要导包
public void testLogin() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name="zhangsan";
String pwd="123";
//3.定义SQL语句
String sql="SELECT * FROM tb_user where username='"+name+"'and password='"+pwd+"'";
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
/**
* 演示SQL注入
* @throws Exception
*/
@Test//要导包
public void testLogin_Inject() throws Exception {//Inject-注入
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name="sdgfghukgm";
String pwd="' or'1'='1";
//3.定义SQL语句
String sql="SELECT * FROM tb_user where username='"+name+"'and password='"+pwd+"'";
System.out.println(sql);
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
如何不让SQL注入呢?下面来看PreparedStatement
String sql = "select * from user where username = ? and password = ?"
PreparedStatement pstmt = conn.prepareStatement(sal);
1. 预编译SQL,性能更高
2. 防止SQL注入: 将敏感字符进行转义
PreparedStatement 预编译功能开启: useServerPrepStmts=true
配置MySQL执行日志(重启mysql服务后生效)
log-output=FILE
general-log=1
general_log_file="D: mysql.log"
slow-query-log=1
slow_query_log_file="D:mysql_slow.log"
long_query_time=2
1.在获取PreparedStatement对象时,将sql语何发送给mysql服务器进行检查,编译(这些步骤很耗时)
2.执行时就不用再进行这些步骤了,速度更快
3.如果sql模板一样,则只需要进行一次检查、编译
举例
package com.svt.jdbc;
import org.junit.Test;
import java.sql.*;
public class JDBCDemo7_PreparedStatement {
@Test//要导包
public void testPreparedStatement() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name="zhangsan";
String pwd="' or'1'='1";
//3.定义SQL语句
String sql="SELECT * FROM tb_user WHERE username= ? AND password= ? ";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql
ResultSet rs = pstmt.executeQuery();
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
@Test//要导包
public void testPreparedStatement2() throws Exception {
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
//useServerPrepStmts=true 参数开启预编译功能
String url="jdbc:mysql:///my_db?useServerPrepStmts=true";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name="zhangsan";
String pwd=" ";
//3.定义SQL语句
String sql="SELECT * FROM tb_user WHERE username= ? AND password= ? ";
//获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//执行sql
ResultSet rs = pstmt.executeQuery();
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
/**
* 演示SQL注入
* @throws Exception
*/
@Test//要导包
public void testLogin_Inject() throws Exception {//Inject-注入
//1.注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接 如果连接的是本机mysql并且端口是默认的3306 可以简化书写
//String url="jdbc:mysql://127.0.0.1:3306/my_db";
String url="jdbc:mysql:///my_db";//有安全隐患的可以在数据库名称后直接加上?useSSL=false 不能有空格
String username="root";
String password="1234";
Connection conn = DriverManager.getConnection(url, username, password);
//接受用户输入的用户名和密码
String name="sdgfghukgm";
String pwd="' or'1'='1";
//3.定义SQL语句
String sql="SELECT * FROM tb_user where username='"+name+"'and password='"+pwd+"'";
System.out.println(sql);
//4.获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5.执行sql
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}