JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。JDBC其实就是java定义的一套和数据库建立连接的规范(接口),各家数据库厂商,想要Java去操作自家数据库,就必须实现这套接口,我们把数据库厂商写的这套实现类,叫做数据库驱动。
返回顶部
JDBC 可做三件事:与数据库建立连接、发送操作数据库的语句并处理结果。
返回顶部
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.导入数据库的驱动jar包
//将下载好的驱动包复制到project下新建的lib文件夹下,右键lib,点击Add as Library
//2.加载驱动jar包,通过放射的方式
//可以省略不写,注册驱动这个动作是Driver里面有个静态代码块在做
/*
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
Class.forName("com.mysql.jdbc.Driver");
//3.获取连接对象
//url的格式:jdbc:mysql://ip地址:端口/库名
//本地连接可以简写 主机名和端口可以省略不写
//String url = "jdbc:mysql:///0316test"
String url = "jdbc:mysql://localhost:3306/0316test";
//数据库用户名
String username = "root";
//密码
String password = "123456";
//把这三个参数传入,返回连接对象
//java.sql 接口 Connection 与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
Connection connection = DriverManager.getConnection(url, username, password);
//4.获取操作对象
//Statement createStatement () 创建一个 Statement 对象来将 SQL 语句发送到数据库。
// Statement 用于执行静态 SQL 语句并返回它所生成结果的对象。
Statement statement = connection.createStatement();
//5.执行SQL语句
//给0316test库中的emp表中插入一条数据
String sql = "INSERT INTO emp VALUES (1006,'李四','工头',200);";
//执行SQL语句
//statement.execute()用来执行所有类型的SQL语句,返回true 或 false
//如果第一个结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回 false
//statement.executeUpdate();用来执行DML,DDL语句,返回影响的行数
//statement.executeQuery(); 用来执行DQl语句 用于产生单个结果集的语句,例如 SELECT 语句。
int i = statement.executeUpdate(sql);//返回改变行数
//判断是否插入成功
if (i > 0) {
System.out.println("success");
} else {
System.out.println("fail");
}
//6.释放资源
connection.close();
statement.close();
}
}
这里给大家普及一个小知识:
Connection Statement PrepareStatement ResultSet
四个接口都是AutoCloseable的子接口
在这四个接口中都提供了close()方法
但是只要连接关闭,所有的操作都自然进行资源释放
也就是说,只需要调用Connection接口的close()方法就可以释放所有资源
返回顶部
结果集对象,是我们执行了查询语句之后返回的一个查询结果对象
ResultSet 对象具有指向其当前数据行的光标。 最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while循环中使用它来迭代结果集。
我们现在数据库中新建一张学生表并插入数据:
CREATE TABLE `students` (
`sname` varchar(20) DEFAULT NULL,
`sage` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO students VALUES("张三",19);
INSERT INTO students VALUES("李四",20);
INSERT INTO students VALUES("王五",18);
-- 学生表
sname sage
------ --------
张三 19
李四 20
王五 18
现在用java来操作这张表:
import java.sql.*;
import java.util.ArrayList;
public class JDBCDemo2 {
public static void main(String[] args) throws Exception {
ArrayList<Students> list = new ArrayList<>();
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///0316test", "root", "123456");
String sql = "select * from students";
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
// ResultSet 结果集对象
//表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
// 可以用next方法来迭代结果集
while (resultSet.next()) {
//一行一行来获取值,1和2表示每行第一列和第二列的值
String sname1 = resultSet.getString(1);
int sage1 = resultSet.getInt(2);
//System.out.println(sname1+"----"+sage1);
// 你也可以通过列名来获取值
String sname2 = resultSet.getString("sname");
int sage2 = resultSet.getInt("sage");
//System.out.println(sname2+"----"+sage2);
//我们从数据库中取出数据,是为了使用这些数据,那么我们新建一个学生类和一张list表来存储学生对象
Students s = new Students(sname1, sage1);
list.add(s);
}
System.out.println(list);
//[Students{name='张三', age=19}, Students{name='李四', age=20}, Students{name='王五', age=18}]
// 释放资源
conn.close();
statement.close();
resultSet.close();
}
}
这是学生类:
/**
* @Author: 伟酱
* @CreateTime: 2019-03-16 21:44
* @Description: TODO
*/
public class Students {
private String name;
private int age;
public Students() {
}
public Students(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
返回顶部
下面来看些关于数据库安全方面的知识,一个案例:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCDemo3 {
public static void main(String[] args) throws Exception {
// students表中已经存储了三行数据,现在我们通过java来查询
//我想要输入学生姓名,然后查找学生信息
System.out.println("请输入姓名:");
Scanner scanner = new Scanner(System.in);
String sname = scanner.nextLine();
sname= "1'='1' or '1'='1";
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///0316test", "root", "123456");
String sql = "select * from students where sname='" + sname + "'";
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {
System.out.println("查找成功");
} else {
System.out.println("没有找到");
}
// 别忘了释放资源
conn.close();
statement.close();
resultSet.close();
}
}
这段代码可以通过在java控制台输入学生姓名去数据库查找信息并返回结果我们来测试一下,这是数据库中已经有的数据:
sname sage
------ --------
张三 19
李四 20
王五 18
请输入姓名:
王麻子
没有找到
请输入姓名:
张三
查找成功
请输入姓名:
1'='1' or '1'='1
查找成功
我们输入这样的字符串竟然返回了查找成功的结果!!
我们称之为SQL注入(所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。)
我们也可以在上面的代码中取消键盘输入插入这样一行代码:
sname= "1'='1' or '1'='1";
相当于在数据库中执行了这样一段SQL语句:
SELECT * FROM students WHERE sname= '1'='1' or '1'='1';
-- 它会返回所有数据
和上面的结果是一致的,都会返回意料之外的结果。其实在开发过程中,我们并不推荐动态拼串,但是,在必要时,我们可以使用预编译来防止注入。
public interface PreparedStatement
extends Statement表示预编译的SQL语句的对象。
SQL语句已预编译并存储在PreparedStatement对象中。
void setString(int parameterIndex,
String x)
throws SQLException
将指定的参数设置为给定的Java String值。
当它发送到数据库时,驱动程序将其转换为SQL VARCHAR或LONGVARCHAR值
(取决于参数相对于VARCHAR值的驱动程序限制的大小)。
参数
parameterIndex - 第一个参数是1,第二个是2,...
x - 参数值
来看升级后的代码:
import java.sql.*;
import java.util.Scanner;
public class JDBCDemo4 {
public static void main(String[] args) throws Exception {
System.out.println("请输入姓名:");
Scanner scanner = new Scanner(System.in);
String sname = scanner.nextLine();
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///0316test", "root", "123456");
//把需要拼串的内容用英文?代替,把sql语句预编译,然后再给?赋值
String sql = "select * from students where sname=?";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1,sname);
//注意这里不要再传参
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
System.out.println("查找成功");
} else {
System.out.println("没有找到");
}
// 释放资源
conn.close();
preparedStatement.close();
resultSet.close();
}
}
再来测试:
请输入姓名:
1'='1' or '1'='1
没有找到
返回顶部
每次都要获取数据库连接对象很麻烦,我们可以把这段代码封装一下,写成一个工具类,让它自动返回连接对象,但是传进去的三个参数不能写死,我们可以把它写成配置文件,在工具类加载时去读取它,如果要对参数进行修改,直接改配置文件就行。
这里读取配置文件有很多方法:
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
public class JDBCUtils {
private static String username;
private static String password;
private static String url;
//1.构造
public JDBCUtils() {
}
//静态代码块,截取url,username,password
static {
try {
FileInputStream in = new FileInputStream("E:\\my0316\\register");
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
String[] split = s.split(";");
username = split[0].split("=")[1];
password = split[1].split("=")[1];
url = split[2].split("=")[1];
Class.forName(split[3]);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//2.我们提供公共的静态方法,来返回一个连接对象
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
}
//3.释放资源-有ResultSet
public static void close(Connection conn, Statement statement, ResultSet resultSet) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
}
//重载,释放资源-没有RresultSet
public static void close(Connection conn, Statement statement) throws SQLException {
if (conn != null) {
conn.close();
}
if (statement != null) {
statement.close();
}
}
}
新建properties文件:register.properties
输入:
username=root
password=123456
url=jdbc:mysql:///0316test
driverclass=com.mysql.jdbc.Driver
// 替换上面的静态代码块即可,其实目的都是读取到正确的连接参数
static{
try {
Properties properties = new Properties();
properties.load(new FileInputStream("E:\\my0316\\register.properties")); //注意配置文件的路径
Class.forName(properties.getProperty("driverclass", "com.mysql.jdbc.Driver"));//给个默认值
username = properties.getProperty("username");
password = properties.getProperty("password");
url = properties.getProperty("url");
} catch (Exception e) {
e.printStackTrace();
}
}
我们来测试一下工具类:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JDBCDemo {
public static void main(String[] args) throws SQLException {
//通过工具类获取连接对象
Connection connection = JDBCUtils.getConnection();
String sql = "insert into users values(?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"张三");
preparedStatement.setString(2,"123456");
int i = preparedStatement.executeUpdate();
if (i>0) {
System.out.println("成功");
} else {
System.out.println("失败");
}
//释放资源
connection.close();
}
}
返回:
成功
返回顶部
https://blog.csdn.net/qq_44238142/article/details/88629552