十、JDBC
1、问题描述
将来我们写sql语句,不能在数据库中写,我们应该将sql语句放到java代码中参与运行,但是sql语句和Java语言是两个不同的语言,所有想要将sql语句放到Java中运行需要用到特定的API
2、JDBC:是一堆接口,是Java操作数据库的标准
步骤
1、导入jdbc的jar包
mysql-connection-java-8.0.25
2、jdbc的核心类
a、DriverManager:驱动类,注册驱动使用
b、Connection接口:连接数据库
c、Statement接口:执行平台,执行sql语句
d、ResultSet接口:处理结果集-->只针对查询操作
1、开发步骤
1、注册驱动:DriverManager类
指明我们操作的是哪款数据库
2、获取连接:Connection接口 ->获取连接对象,连接数据库
a:DriverManager中的方法
static Connection getConnection(String Url,String User,String password) 获取连接
b、参数:
url:指明我门要操作的哪个数据库(地址)
user:用户
password:数据库密码
3、准备sql---->sql语句(insert、update、delete)
4、获取执行平台 ---> Statement接口---->执行sql语句
a、获取:用到的是Connection中的方法 ---> Statement CreateStatement();
b、
5、执行sql-->Statement接口中的方法
a、int executeUpdate(String sql) --->增删改操作
b、ResultSet executeQuery(String sql)---->查询操作,返回的是结果集
6、处理结果 --->ResultSet接口
boolean next();---->判断结果集中有没有下一个数据
7、关闭资源
a、关闭结果集:ResultSet
b、关闭执行平台:Statement
c、关闭连接对象:Connection
2、JDBC具体流程
创建数据库
CREATE TABLE `user`(
uid INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
`password` VARCHAR(20)
);
1、注册驱动:Drivermanafer类
static void registerDriver(Driver driver)
a、参数:Driver接口
需要传递Driver接口实现类的对象,但是在API文档上没有体现Driver的实现类
所以需要传递mysql核心jar包中的Driver类,此类在com.mysql.cj.jdbc包小,
此类实现了java.sql.Driver接口
注意:
当new com.mysql.cj.jdbc.Driver是底层有一个静态代码块
在静态代码块中写一个DriverManager.registerDriver(new Driver());
也就意味着,如果我们使用DriverManager.registerDriver(new Driver());注册驱动
到最后我们就直接注册了两次,没必要
解决办法:统一用反射技术,获取Driver的class对象
Class.forName("com.mysql.cj.jdbc.Driver");
2.获取连接:DriverManager类中的方法
static Connection getConnection(String url, String user, String password):获取
连接
url:指明我们操作的是哪个库,写的是库的url(地址)
jdbc:mysql://localhost:3306/数据库名字?参数1&参数2
user:指明数据库的用户名
password:指明数据库的密码
String url = "jdbc:mysql://localhost:3306/230417_java3";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url,user,password);
System.out.println(connection);
常见问题:
3、JDBC实现增删改
@Test
public void insert() throws Exception{
/**
* 1、注册驱动:DriverManager类
*/
Class.forName("com.mysql.cj.jdbc.Driver");
/**
* 2、获取连接:DriverManager类中的方法
*/
String url="jdbc:mysql://localhost:3306/java_JDBC";
String user="root";
String passwod="123456";
Connection connection = DriverManager.getConnection(url,user,passwod);
/**
* 3、准备sql
*/
String sql="insert into user (username,password) values ('zhangsan','123456')";
/**
* 4、获取执行平台:Statement接口 -> 执行sql语句
* 用到的是Connection中的方法
* Statement createStatement()
*/
Statement statement = connection.createStatement();
/**
* 5、执行sql:Statement接口中的方法
* int executeUpdate(String sql) -> 针对于增删改操作
*/
int i=statement.executeUpdate(sql);
/**
* 6、处理结果集合,但是增删改查不需要处理结果集
*/
/**
* 7、关闭资源
*/
statement.close();
connection.close();
}
4、JDBC实现查询操作
1.Statement中的方法:
ResultSet executeQuery(String sql)->专门针对于查询
2.处理结果集
a.方法:boolean next() -> 判断结果集中有没有下一个数据
b.获取:
int getInt(int columnIndex)-> 获取第几列的数据 -> 获取int型列的数据
int getInt(String columnLabel) -> 获取指定列名的数据,写列名 -> 获取int型列的数据
String getString(int columnIndex)-> 获取第几列的数据
String getString(String columnLabel)-> 获取指定列名的数据,写列名
Object getObject(int columnIndex)-> 获取第几列的数据
Object getObject(String columnLabel)-> 获取指定列名的数据,写列名
@Test
public void query() throws Exception{
//1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接
String url="jdbc:mysql://localhost:3306/java_JDBC";
String user="root";
String passwod="123456";
Connection connection = DriverManager.getConnection(url, user, passwod);
//3、准备sql
String sql="select * from user";
//4、获取执行平台
Statement statement = connection.createStatement();
//5、执行sql
ResultSet rs = statement.executeQuery(sql);
//6、处理结果集
while (rs.next()){ //获取下一行
int uid=rs.getInt(1);
String username = rs.getString("username");
String password = rs.getString(3); //获取第3列的数据
System.out.println(uid);
System.out.println(username);
System.out.println(password);
}
//7、关闭资源
rs.close();
statement.close();
connection.close();
}
5、封装工具类
package com.java.utils;
import java.sql.*;
public class JDBCUtils {
//将静态变量定义在类种,声明周期是与类相同的,如果定义在静态代码块中,只能在静态代码块中使用,属于局部变量
private static String url=null;
private static String user=null;
private static String passwod=null;
//定义在静态代码块中,优先main数据加载,且只加载一次
static {
//1、注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接
//初始化静态变量
url="jdbc:mysql://localhost:3306/java_JDBC";
user="root";
passwod="123456";
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection(){
//try-catch中的对象作用域只能在内部使用,所以需要在外部进行创建对象
Connection connection=null;
//由于url, user, passwod是定义在静态代码块中,在静态方法中无法调用,因此先定义在静态变量,通过静态代码块进行赋值,才能被静态方法进行调用
try {
connection = DriverManager.getConnection(url, user, passwod);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//关闭资源
public static void Close(Connection connection, Statement statement, ResultSet resultSet){
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Test
public void insert1() throws Exception{
/**
* 1、注册驱动:DriverManager类
*/
/**
* 2、获取连接:DriverManager类中的方法
*/
Connection connection = JDBCUtils.getConnection();
/**
* 3、准备sql
*/
String sql="insert into user (username,password) values ('lisi','123123')";
/**
* 4、获取执行平台:Statement接口 -> 执行sql语句
* 用到的是Connection中的方法
* Statement createStatement()
*/
Statement statement = connection.createStatement();
/**
* 5、执行sql:Statement接口中的方法
* int executeUpdate(String sql) -> 针对于增删改操作
*/
int i=statement.executeUpdate(sql);
/**
* 6、处理结果集合,但是增删改查不需要处理结果集
*/
/**
* 7、关闭资源
*/
JDBCUtils.Close(connection,statement,null);
}
6、获取最新添加的数据的id
1、格式
select last_insert_id()
2、注意:
a、获取最新加载数据id时,id需要主键增长
b、获取最新添加数据id时,添加的最新数据的id列不要自己指定添加,需要依靠自增去自动维护
7、PreparedStatement预处理对象
登录案例
package com.java;
import com.java.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Demo02_JDBC {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
//采用nextLine是用于存放一行String类型数据时能够点击空格输入,
// 如果是next()则无法进行输入空格,点击空格自行结束输入
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password=scanner.nextLine();
Connection connection = JDBCUtils.getConnection();
String sql="select * from user where username= '"+username+"'and password= '"+password+"'";
System.out.println(sql);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
//只能查看一个数据,如果是有数据则进行判空操作判断是否登录成功
if(resultSet.next()){
System.out.println("登录成功!");
}else {
System.out.println("登录失败!");
}
JDBCUtils.Close(connection,statement,resultSet);
}
}
(1)sql注入
密码输入:111' or '1' = '1 以上程序不行了->sql注入
因为:' or '1' = '1恒为真
(2)使用预处理对象(PreparedStatement)实现操作
1.概述:
PreparedStatement接口 继承 Statement接口
2.获取:Connection中的方法
PreparedStatement prepareStatement(String sql)
3.特点:
写sql语句的时候支持在sql中写占位符 ?
4.为?赋值:
void setObject(int parameterIndex, Object x)
parameterIndex:代表的是第几个?
x:为指定?赋的值
5.执行sql方法:
int executeUpdate() -> 针对增删改
ResultSet executeQuery() -> 针对查询
package com.java;
import com.java.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class Demo03_JDBC {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
//采用nextLine是用于存放一行String类型数据时能够点击空格输入,
// 如果是next()则无法进行输入空格,点击空格自行结束输入
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password=scanner.nextLine();
Connection connection = JDBCUtils.getConnection();
String sql="select * from user where username=? and password =?";
System.out.println(sql);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//为?赋值
preparedStatement.setObject(1,username);
preparedStatement.setObject(2,password);
ResultSet resultSet = preparedStatement.executeQuery();
//只能查看一个数据,如果是有数据则进行判空操作判断是否登录成功
if(resultSet.next()){
System.out.println("登录成功!");
}else {
System.out.println("登录失败!");
}
JDBCUtils.Close(connection,preparedStatement,resultSet);
}
}
(3)JDBC工具类结合Properties文件
创建资源路径
编写配置文件
driverclass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/java_JDBC
username=root
password=123456
编写工具类
package com.java.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils1 {
//将静态变量定义在类种,声明周期是与类相同的,如果定义在静态代码块中,只能在静态代码块中使用,属于局部变量
private static String url=null;
private static String user=null;
private static String passwod=null;
//定义在静态代码块中,优先main数据加载,且只加载一次
static {
//1、注册驱动
try {
Properties properties=new Properties();
//文件加载
InputStream in = JDBCUtils1.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(in);
Class.forName(properties.getProperty("driverclass"));
url=properties.getProperty("url");
user=properties.getProperty("username");
passwod=properties.getProperty("password");
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection(){
//try-catch中的对象作用域只能在内部使用,所以需要在外部进行创建对象
Connection connection=null;
//由于url, user, passwod是定义在静态代码块中,在静态方法中无法调用,因此先定义在静态变量,通过静态代码块进行赋值,才能被静态方法进行调用
try {
connection = DriverManager.getConnection(url, user, passwod);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//关闭资源
public static void Close(Connection connection, Statement statement, ResultSet resultSet){
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试
@Test
public void insert2() throws Exception{
/**
* 1、注册驱动:DriverManager类
*/
/**
* 2、获取连接:DriverManager类中的方法
*/
Connection connection = JDBCUtils1.getConnection();
/**
* 3、准备sql
*/
String sql="insert into user (username,password) values (?,?)";
/**
* 4、获取执行平台:Statement接口 -> 执行sql语句
* 用到的是Connection中的方法
* Statement createStatement()
*
* PreparedStatement接口 继承 Statement接口
* Connection中的方法
* PreparedStatement prepareStatement(String sql)
*/
PreparedStatement preparedStatement = connection.prepareStatement(sql);
/**
* 5、执行sql:Statement接口中的方法
* int executeUpdate(String sql) -> 针对于增删改操作
*
* 设置?占位符中的字段值
*/
preparedStatement.setObject(1,"王五");
preparedStatement.setObject(2,"111222");
int i=preparedStatement.executeUpdate();
/**
* 6、处理结果集合,但是增删改查不需要处理结果集
*/
/**
* 7、关闭资源
*/
JDBCUtils1.Close(connection,preparedStatement,null);
}