之前我是通过控制台和mysql可视化工具来操作数据库,而JDBC 是 Java 访问数据库的标准规范,通过它,我可以用java程序来访问数据库.
使用它之前,需要先去官网下载jar包:
https://dev.mysql.com/downloads/file/?id=494900 然后按照下图导入包:
值得注意的是mysql版本是8.0.x的话,jar也得下载8.0.x版本的jar包.不然会报错.
driverManager类主要用来创建数据库连接,如下代码就是取到了数据库的连接:
public class Demo1 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/db2";
Connection connection = DriverManager.getConnection(url, "root", "Huan100861!");
//com.mysql.jdbc.JDBC4Connection@68de145
System.out.println(connection);
}
}
ur的解析:
获取到connnection对象后,可以进而获取到statement对象,它用来执行sql语句:
//1,创建连接
Connection conn=null;
Statement statement =null;
try{
conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root","123");
//2,通过连接对象得到语句对象
statement =conn.createStatement();
//3,通过语句对象发送sql语句给服务器
//4,执行sql
statement.executeUpdate("create table student(id int primary key auto_increment," +
"name varchar(20) not null,gender boolean,birthday date)");
System.out.println("创建表成功");
}catch(SQLException e) {
e.printStackTrace();
}
//1,创建连接对象
Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root","123");
//2,创建statement语句对象
Statement statement=connection.createStatement();
//3,执行sql语句:executeUpdate(sql)
int count=0;
count+=statement.executeUpdate("insert into student values(null,'孙悟空',1,'2024-03-24')");
count+=statement.executeUpdate("insert into student values(null,'白骨精',0,'2024-03-25')");
count+=statement.executeUpdate("insert into student values(null,'猪八戒',1,'2024-03-26')");
count+=statement.executeUpdate("insert into student values(null,'嫦娥',0,'2024-03-27')");
System.out.println("插入了"+count+"条记录");
//1,得到连接对象
Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/db2","root","123");
//得到statement对象
Statement statement=connection.createStatement();
ResultSet res=statement.executeQuery("select * from student");
System.out.println(res);
while(res.next()){
int id=res.getInt("id");
String name=res.getString("name");
boolean gender=res.getBoolean("gender");
Date birthday=res.getDate("birthday");
System.out.println(id+'+'+name+'+'+gender+'+'+birthday);
}
需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
释放原则:先开的后关,后开的先关。ResultSet Statement Connection
放在哪个代码块中:finally 块
try {
res.close();
statement.close();
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
五,数据库工具类 JdbcUtils
上文我们写了很多重复的代码,包括创建连接,取得statement对象,还有连接的关闭等,都可以抽离出来,封装成一个单独的类.
package com.itheima.utils;
import java.sql.*;
//访问数据库的工具类
public class JdbcUtils {
//可以把几个字符串定义成常量:用户名,密码,URL,驱动类
private static final String USER = "root";
private static final String PWD = "123";
private static final String URL = "jdbc:mysql://localhost:3306/db2";
//得到数据库连接
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(URL,USER,PWD);
}
//关闭所有打开的资源-连接和语句
public static void close(Connection conn, Statement stmt){
//关闭之前要判断
if(stmt!=null){
try{
stmt.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
//关闭所有查询结果和连接+语句
public static void close(Connection conn, Statement stmt, ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
close(conn,stmt);
}
}
使用的示例,用户登录. 这里先准备数据:
create table user (
id int primary key auto_increment,
name varchar(20),
password varchar(20)
)
insert into user values (null,'jack','123'),(null,'rose','456');
然后编写登录登录类:
package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class Demo7Login {
//从控制台上输入用户名和方法
public static void main (String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String name=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
login(name,password);
}
//登录的方法
public static void login(String name,String password){
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try{
connection= JdbcUtils.getConnection();
statement=connection.createStatement();
String sql="select * from user where name='"+name+"' and password='"+password+"';";
System.out.println(sql);
rs=statement.executeQuery(sql);
if (rs.next()) {
System.out.println("登录成功,欢迎您:" + name);
} else {
System.out.println("登录失败");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//d) 释放资源
JdbcUtils.close(connection, statement, rs);
}
}
}
但是这种写法,我们是简单地拼接sql语句,会带来sql注入的漏洞.
请输入用户名:
newboy
请输入密码:
a' or '1'='1
select * from user where name='newboy' and password='a' or '1'='1'
当我们输入这个密码时,居然也能登录成功.这是因为这条sql语句的where后变成了true,所以返回了全表. 为了避免这一个问题,就从statement接口处继承了PreparedSatement 接口,由它来操作数据库.
六,使用PreparedSatement 来执行sql
这样一来,就能避免直接拼接sql带来的sql注入的问题:
package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.*;
import java.util.Scanner;
public class Demo8Login {
//从控制台上输入用户名和方法
public static void main (String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String name=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
login(name,password);
}
//登录的方法
public static void login(String name,String password) {
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
String sql = "select * from user where name=? and password=?";
ps = connection.prepareStatement(sql);
ps.setString(1, name);
ps.setString(2, password);//替换?
resultSet = ps.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功,欢迎您:" + name);
} else {
System.out.println("登录失败");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
//d) 释放资源
JdbcUtils.close(connection, ps, resultSet);
}
}
}
七,事务的jdbc处理
之前学过,事务的关键就是要开启事务,并且事务可以回滚.
package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo12Transaction {
//没有异常,提交事务,出现异常回滚事务
public static void main(String[] args) {
//1) 注册驱动
Connection connection = null;
PreparedStatement ps = null;
try {
//2) 获取连接
connection = JdbcUtils.getConnection();
//3) 开启事务
connection.setAutoCommit(false);
//4) 获取到 PreparedStatement
//从 jack 扣钱
ps = connection.prepareStatement("update account set balance = balance - ? where name=?");
ps.setInt(1, 500);
ps.setString(2,"Jack");
ps.executeUpdate();
//出现异常
System.out.println(100 / 0);
//给 rose 加钱
ps = connection.prepareStatement("update account set balance = balance + ? where=name=?");
ps.setInt(1, 500);
ps.setString(2,"Rose");
ps.executeUpdate();
//提交事务
connection.commit();
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
try {
//事务的回滚
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("转账失败");
}
finally {
//7) 关闭资源
JdbcUtils.close(connection,ps);
}
}
}
从这里来看的话,就是connection.setAutoCommit(false);false表示关闭事务自动提交,也就是开启手动事务的意思.后续要提交则connection.commit();,要回滚则connection.rollback();