❤️💕💕java的学习指南,从入门到大师篇章。Myblog:http://nsddd.top
[TOC]
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
这个时候就可以导入:
Class.forName("com.mysql.jdbc.Driver");
此时会有异常,IDEA贴心提醒,担心你后面写的东西错了,添加异常到方法签名
package org.example;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
}
}
我们需要对数据库进行操作
select * from students;
select * from students where id < 10 and score > 80;
update students set score=88 where id = 1;
select * from students where id = 1;
上面的代码可以将id = 1
的学生分数改为88,将sql写入Java代码中:
选择这个jar
添加库
package org.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println("Hello world!");
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//定义sql语句
String sql = "update students set score=98 where id = 1;";
//获取执行sql对象statement
Statement stem = conn.createStatement();
//执行sql -- 返回值受影响的行数 -- 如果返回为1 说明1行sql执行成功
int count = stem.executeUpdate(sql);
//处理结果
System.out.println(count);
//释放资源 -- 先释放stml再释放conn
stem.close();
conn.close();
}
}
执行代码:
Hello world!
1
进程已结束,退出代码0
我们马上去查询数据库 可以看出来数据会更新的
select * from students where id = 1
id|name|gender|grade|score|
--+----+------+-----+-----+
1|小贝 | 0| 3| 88|
🔦 到目前为止,算是顺利执行了,有一点需要提醒,就是需要在
我们需要先去了解一下jdk
官方文档,上面对各个接口有很多解释
DriverManager
类:依据数据库的不同,管理JDBC驱动Connection
接口:负责连接数据库并且担任传送数据的任务Statement
接口:由Connection产生、负责执行SQL语句ResultSet
接口:从数据源读取数据
- 注册驱动
- 获取数据库连接
注册驱动
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
5.0版本之后可以省略,因为自带了,不需要再写了
获取数据库连接
/获取连接
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
jdbc:mysql://localhost:49156/learnjdbc
:如果是本地且3306,那么可以简写jdbc:mysql:///
(我的是连接docker)- 配置
useSSL=false
参数,禁止用安全连接方式,解决警告提醒
//获取执行sql对象statement
Statement stem = conn.createStatement();
- 执行
SQL
的对象 - 管理事务
普通执行SQL对象
Statement createStatement()
预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement createStatement()
执行存储过程的对象
CallableStatement prepareCall(sql)
事务操作:
mysql默认自动提交事务
- 开启事务:
begin;/start transaction
- 提交事务:
commit
- 回滚事务:
rollback
JDBC事务管理:Connection接口中定义了3个对应方法
- 开启事务:
setAutoCommit(boolean autoCommit)
ture
: 自动提交false
: 手动提交
- 提交事务:
commit
- 回滚事务:
rollback()
有提个问题:当你出现错误,如何检测错误并且回滚?
我们使用try - catch
捕获
// 事务 -- 下面两条数据要么同时成功,要么同时失败
try {
//开启事务
conn.setAutoCommit(false);
//执行代码
int count1 = stem.executeUpdate(sq2);
System.out.println(count1);
int count2 = stem.executeUpdate(sql2);
System.out.println(count2);
//提交事务
conn.commit();
} catch (SQLException e) {
//回滚事务
conn.rollback();
throw new RuntimeException(e);
}
完整代码
package org.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class jdbc1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println("Hello world!");
//注册驱动
// Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//定义sql语句
String sql1 = "update students set score=100 where id = 1;";
String sql2 = "update students set score=100 where id = 2;";
//获取执行sql对象statement
Statement stem = conn.createStatement();
// 事务 -- 下面两条数据要么同时成功,要么同时失败
try {
//开启事务
conn.setAutoCommit(false);
//执行代码
int count1 = stem.executeUpdate(sql2);
System.out.println(count1);
int count2 = stem.executeUpdate(sql2);
System.out.println(count2);
//提交事务
conn.commit();
} catch (SQLException e) {
//回滚事务
conn.rollback();
throw new RuntimeException(e);
}
//提交事务
//释放资源 -- 先释放stml再释放conn
stem.close();
conn.close();
}
}
执行:
Hello world!
1
1
进程已结束,退出代码0
1 小贝 0 3 100
2 小强 0 2 100
甚至,我们可以改一下:
try {
//开启事务
conn.setAutoCommit(false);
//执行代码
int count1 = stem.executeUpdate(sql2);
System.out.println(count1);
int aa = 123/0;
int count2 = stem.executeUpdate(sql2);
System.out.println(count2);
//提交事务
conn.commit();
} catch (SQLException e) {
//回滚事务
conn.rollback();
throw new RuntimeException(e);
} finally {
System.out.println("hello word , 执行完成 ");
//释放资源 -- 先释放stml再释放conn
stem.close();
conn.close();
}
finally是后面必须要执行的, int aa = 123/0;
是一个溢出错误,这个溢出是静态语言是没办法检测出来的
int count1 = stem.executeUpdate(sql1);
System.out.println(count1);
int count2 = stem.executeUpdate(sql2);
System.out.println(count2);
int executeUpdate(sql):执行DML、DDL语句;
返回值:
- DML语句影响的行数
- DDL语句执行后, 执行成功也可能返回0
我们可以写一个测试类
package org.example;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Jdbc2 {
@Test
public void testDML() throws SQLException {
System.out.println("Hello world!");
//注册驱动
// Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//定义sql语句
String sql = "update students set score=10000 where id = 1;";
//获取执行sql对象statement
Statement stem = conn.createStatement();
//执行sql -- 返回值受影响的行数 -- 如果返回为1 说明1行sql执行成功
int count = stem.executeUpdate(sql);
//处理结果
System.out.println(count);
//释放资源 -- 先释放stml再释放conn
stem.close();
conn.close();
}
}
我们可以把处理结果修改一下
if (count > 0) {
System.out.Println("修改成功");
}else {
System.out.Println("修改失败");
}
更新记录时要小心。如果省略该
WHERE
子句,所有记录都将被更新!
删除记录
String sql = "delete from students where id = 2";
添加记录
#1.指定列名和要插入的值:
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
#2. 如果要为表的所有列添加值,则不需要在 SQL 查询中指定列名。但是,请确保值的顺序与表中列的顺序相同。在这里, INSERT INTO语法如下:
INSERT INTO table_name
VALUES (value1, value2, value3, ...);
创建数据库操作
package org.example;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Jdbc2 {
@Test
public void testDML() throws SQLException {
System.out.println("Hello world!");
//注册驱动
// Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//定义sql语句
String sql = "create database db2";
//获取执行sql对象statement
Statement stem = conn.createStatement();
//执行sql -- 返回值受影响的行数 -- 如果返回为1 说明1行sql执行成功
int count = stem.executeUpdate(sql);
//处理结果
if (count > 0) {
System.out.println("创建数据库成功");
}else {
System.out.println("创建数据库失败");
}
//释放资源 -- 先释放stml再释放conn
stem.close();
conn.close();
}
}
但是删除数据库的时候,还是为0
仔细想想,DDL执行后删除了不就是0 嘛
int count = stem.executeUpdate(sql);
- 封装了DQL查询语句的结果
ResultSet stmt.executeUpdate(sql): 执行DQL语句,返回ResultSet对象
- 获取返回结果
boobean next()
+ 将光标从当前位置向前移动一位
+ 判断当前行是否为有效行
+ true:有效行
+ false: 无效行
xxx getXxx(参数):获取数据
xxx:数据类型:如 int getInt(参数); String getString(参数)
+ int:列的编号,从1开始
+ String:列的名称
光标是移动的,从0
开始,依次往下,所以代码是循环:
while(rs.next()) {
//获取数据
rs.getXxx
}
use learnjdbc;
select * from students ;
当前数据库的表结构
关键部分:
//6. 处理结果,遍历所有
//6.1 光标向下移动一行,且判断当前行是否有数据
while (rs.next()) {
//6.2 获取数据
double id = rs.getDouble(1);
String name = rs.getString(2);
Boolean gender = rs.getBoolean(3);
int grade = rs.getInt(4);
int score = rs.getInt(5);
System.out.println(id + " " + name + " " + gender + " " + grade + " " + score);
}
可以写ID,也可以写名称
package org.example;
import org.junit.Test;
import java.sql.*;
/**
* java API result
*/
public class Jdbc3 {
@Test
public void testDML() throws SQLException {
String url = "jdbc:mysql://localhost:49156/learnjdbc";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//3. 定义sql
String sql = "SELECT * FROM students where id < 10"; //查询
//4. 获取对象
Statement stmt = conn.prepareStatement(sql);
//执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果,遍历所有
//6.1 光标向下移动一行,且判断当前行是否有数据
while (rs.next()) {
//6.2 获取数据
Long id = rs.getLong("id");
String name = rs.getString("name");
int gender = rs.getInt("gender");
int grade = rs.getInt("grade");
int score = rs.getInt("score");
System.out.println(id + " " + name + " " + gender + " " + grade + " " + score);
}
// 7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
查询账户数据,封装为Account对象,存储到ArrayList集合中
对于数据封装的对象,放在一个包:com.nsddd.top
- 定义实体类
- 查询数据,并且封装到
account
对象 - 将
account
对象存到arraylist
集合中
Jdb4
package org.example;
import org.junit.Test;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* java API result
*/
public class Jdbc4 {
@Test
public void testDML() throws SQLException {
String url = "jdbc:mysql://localhost:49156/db3";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
//3. 定义sql
String sql = "SELECT * FROM java"; //查询
//4. 获取对象
Statement stmt = conn.prepareStatement(sql);
//执行sql
ResultSet rs = stmt.executeQuery(sql);
//创建一个集合
List<Account> list = new ArrayList<>();
//6. 处理结果,遍历所有
//6.1 光标向下移动一行,且判断当前行是否有数据
while (rs.next()) {
//创建对象
Account account = new Account();
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString(2);
int phone = rs.getInt(3);
// int grade = rs.getInt("grade");
// int score = rs.getInt("score");
//对象赋值
account.setId(id);
account.setName(name);
account.setPhone(phone);
//toString
System.out.println(account.toString());
//存入集合 --- 对象
list.add(account);
}
//打印集合
System.out.println(list);
// 7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
Account
package org.example;
public class Account {
private int id;
private String name;
private int phone;
@Override
public String toString() {
return "account{" +
"id=" + id +
", name='" + name + '\'' +
", phone=" + phone +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
this.phone = phone;
}
}
打印:
account{id=1, name='xiongxinwei', phone=17}
account{id=1, name='xiongxinwei', phone=17}
account{id=1, name='xiongxinwei', phone=17}
account{id=2, name='zhangsan', phone=112}
account{id=1, name='xiongxinwei', phone=17}
account{id=2, name='zhangsan', phone=112}
account{id=1, name='xiongxinwei', phone=17}
account{id=2, name='zhangsan', phone=112}
[account{id=1, name='xiongxinwei', phone=17}, account{id=1, name='xiongxinwei', phone=17}, account{id=1, name='xiongxinwei', phone=17}, account{id=2, name='zhangsan', phone=112}, account{id=1, name='xiongxinwei', phone=17}, account{id=2, name='zhangsan', phone=112}, account{id=1, name='xiongxinwei', phone=17}, account{id=2, name='zhangsan', phone=112}]
PreparedStatement
继承于Statement
作用:预编译SQL语句并且执行:防止SQL注入问题
- 预编译:性能更高
- 防止sql注入:将敏感字符进行转义
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以来达到对服务器进行攻击的方式
解决SQL注入我们首先要明白为什么发生sql注入:
因为
需要在mysql中开启,具体谷歌sou'suo
useServerPrepStmts=true
完成用户登陆
select * from tb_user where username = "xiongxiwne" and password="1234"
关键代码
String name = "xiongxinwei";
String pwd = "123421";
//定义sql
String sql = "select * from tb_user where username = ? and password = ?";
//获取pstmt对象
PreparedStatement pstmt = conn.preparedStatement(sql);
//设置 ? 占位符 -- 两个?
pstmt.setString(1,name);
pstmt.setString(2,pwd);
- 在获取PreparedStatement对象时候,将sql语句发送到MySQL服务器: 进行检测,编译
- 执行时就不用再进行这些步骤,速度更快
- 如果sql模板都一样,只需要进行一次检查