JDBC
JDBC是什么呢?
Java Database Connection = Java 数据库连接
JDBC就是JAVA帮助我们去操作数据库的一套接口,这个仅仅是接口,没有实现
如何使用JDBC
1. 注册驱动
DriverManager.registerDriver(new Driver());
//优化方案
// Class.forName("com.jdbc.mysql.Driver");
2. 获取连接
Connection connection = DriverManager.getConnection("url","username","password");
3. 创建Statement对象,构建sql请求
Statement statement = connection.getStatement();
4. 执行sql,拿到返回结果
Resultset resultSet = statement.executeQuery("select * from users");
// 增删改 都用这个
// int affectedRows = statement.executeUpdate("insert into users values ('','')");
5. 处理返回结果,解析
Boolean flag = resultSet.next();
String name = resultSet.getString("name");
resultSet.next();
String name = resultSet.getString("name");
6. 关闭资源
案例一
最原始的JDBC案例
public class JDBCTest1 {
/**
* 第一个连接数据库Mysql的JDBC案例
* @param args
*/
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 1. 注册驱动
DriverManager.registerDriver(new Driver());
// 2. 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc?useSSL=false","root","123456");
// 3. 创建statement对象
statement = connection.createStatement();
// 4. 执行sql语句
String sql = "select * from t_students";
resultSet = statement.executeQuery(sql);
// 5. 结果返回结果
// 移动游标
resultSet.next();
String name = resultSet.getString("name");
System.out.println("name:" + name);
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 释放资源
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
案例二
完成完整的结果的解析
resultSet = statement.executeQuery(sql);
// 5. 结果返回结果
// 移动游标
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
// 这个地方是列名,不是对象的成员变量名
Float english = resultSet.getFloat("english");
String className = resultSet.getString("class");
Float math = resultSet.getFloat("math");
Float chinese = resultSet.getFloat("chinese");
// 赋值
Student stu = new Student();
stu.setId(id);
stu.setName(name);
stu.setClassname(className);
stu.setChinese(chinese);
stu.setMath(math);
stu.setEnglish(english);
// 放进List集合中
students.add(stu);
}
案例三
把连接、用户名、密码都放到配置文件里面去
private static String url;
private static String username;
private static String password;
static {
try {
// 加载配置文件
Properties properties = new Properties();
// FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
// properties.load(fileInputStream);
// 通过类加载器去获取
ClassLoader classLoader = JDBCTest3.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("jdbc.properties");
properties.load(inputStream);
// 取值 赋值
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
案例四
升级为JDBCUtils
import com.mysql.jdbc.Driver;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String username;
private static String password;
private static String driverName;
static {
try {
// 加载配置文件
Properties properties = new Properties();
// 通过类加载器去获取
ClassLoader classLoader = JDBCTest3.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("jdbc.properties");
properties.load(inputStream);
// 取值 赋值
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
driverName = properties.getProperty("driverName");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection(){
Connection connection = null;
// 1. 注册驱动
try {
Class.forName(driverName); // = "new Driver()"
// DriverManager.registerDriver(new Driver());
// 2. 获取连接
connection = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return connection;
}
// 释放资源
public static void releaseSources(Connection connection, Statement statement, ResultSet resultSet){
// 释放资源
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试工具 JUNIT
作用:用来测试,测试我们的接口功能是不是正常的
导包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
写测试类
测试类提供的几个注解执行的顺序
import org.junit.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
/**
* @Test注解有几个限制
* 1. 修饰的方法必须是public
* 2. 修饰的方法无参
* 3. 修饰的方法无返回值
*/
@Test
public void test01() throws SQLException {
Connection connection = JDBCUtils.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from t_students");
while (resultSet.next()){
String name = resultSet.getString("name");
System.out.println("name:" + name);
}
}
@Test
public void test02() throws SQLException {
Connection connection = JDBCUtils.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from t_students");
while (resultSet.next()){
String name = resultSet.getString("name");
System.out.println("name:" + name);
}
}
/**
* 这个什么时候执行? 在@Test注解修饰的方法执行结束之后,执行了几个@Test修饰的方法,就有几次执行
*/
@After
public void destory(){
System.out.println("after");
}
/**
* 这个什么时候执行? 在@Test注解修饰的方法执行结束之前,执行了几个@Test修饰的方法,就有几次执行
*/
@Before
public void init(){
System.out.println("Before");
}
/**
* 在这个测试类结束的时候执行,只会执行一次
*/
@AfterClass
public static void afterClass(){
System.out.println("AfterClass");
}
/**
* 在这个测试类开始的时候执行,只会执行一次
*/
@BeforeClass
public static void beforeClass(){
System.out.println("beforeClass");
}
}
通过JDBC进行增删改查
import org.junit.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC2 {
static Connection connection = null;
static Statement statement = null;
// 初始化资源
@BeforeClass
public static void init() throws SQLException {
connection = JDBCUtils.getConnection();
statement = connection.createStatement();
}
// 关闭资源
@AfterClass
public static void destory(){
JDBCUtils.releaseSources(connection,statement,null);
}
// 新增记录
@Test
public void testInsertStu() throws SQLException {
String sql = "insert into t_students values (8,'柯镇恶','三班',70,20,30)";
// 返回的结果是影响的行数
int affectedRows = statement.executeUpdate(sql);
System.out.println("影响的行数:" + affectedRows);
}
// 删除记录
@Test
public void testDeleteStu() throws SQLException {
String sql = "delete from t_students where id > 6";
// 返回的结果是影响的行数
int affectedRows = statement.executeUpdate(sql);
System.out.println("影响的行数:" + affectedRows);
}
// 修改记录
@Test
public void testUpdate() throws SQLException {
String sql = "update t_students set name = '老顽童' where id = 1";
int affectedRows = statement.executeUpdate(sql);
System.out.println("影响的行数:" + affectedRows);
}
// 查询记录
}
对象解析
DriverManager
驱动管理器,提供了两个API
第一个API是注册驱动
DriverManager.registerDriver(new Driver());
第二个API是获取连接
Connection conn = DriverManager.getConnection(url,username,password);
url的写法:jdbc:mysql://localhost:3306/dbName?useSSL=false&characterEncoding=utf-8&serverTimezone=UTC
Connection
这个就是一个连接对象,它表示了我们Java程序和Mysql服务器之间的连接
获取statement对象
Statement statement = connection.createStatement();
还有事务相关的API,以及预编译相关的API
Statement
这个对象用于我们的JDBC向数据库发送SQL语句,并执行获取返回结果
// 使用ResultSet对象来接收查询的结果
ResultSet resultSet = statement.executeQuery(String sql);
// 影响的行数
int affectedRows = statement.executeUpdate(String sql);
ResultSet
这个对象是用来封装查询的结果
resultSet.next(); 这个API就类似于我们的Iterator里面维护的游标,执行一次next() 方法,游标就移动一个位置
resultSet.getInt(String columnName);
resultSet.getString(String columnName);
还提供了一些API,帮我们快速的操作ResultSet
resultSet.Previous() 移动到前一行
resultSet.beforeFirst() 移动到最前面
resultSet.afterLast(); 移动到最后面
数据库注入问题
我们使用statement.excuteQuery(String sql) 这个API的时候,假如我们的sql是由字符串拼接而来, 那么在我们拼接字符串的时候,假如字符串里面加入了 or 1=1 这样的关键字,那么就会去做全局匹配,可能就会导致我们的sql语句跳过验证逻辑,产生安全隐患
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 模拟数据库注入的问题
*/
public class JDBCTest3 {
static Connection connection = null;
static Statement statement = null;
@BeforeClass
public static void testBefore() throws SQLException {
connection = JDBCUtils.getConnection();
statement = connection.createStatement();
}
@AfterClass
public static void destory(){
JDBCUtils.releaseSources(connection,statement,null);
}
// 查询用户名和密码
public Boolean login(String username,String password) {
// String sql = "select * from user where username = '"+ username + "' and password = '"+password + "'";
String sql = "select * from user where username = %s and password = %s";
String newUsername = "'" + username + "'";
String newPassword = "'" + password + "'";
//
String trueSql = String.format(sql, newUsername, newPassword);
ResultSet resultSet = null;
try {
resultSet = statement.executeQuery(trueSql);
// resultSet.next() 如果为true,那么就表示登录成功,也就是说这个时候数据库里面有数据
if (resultSet.next()) {
System.out.println("匹配上了,登录成功,用户名:" + resultSet.getString("username"));
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
@Test
public void testLogin(){
Boolean ret = login("l", "l");
System.out.println("ret:" + ret);
}
/**
* 数据库的注入问题
*
* 发现在密码后面加入 1=1 不安全,这种问题就是数据注入问题
*/
@Test
public void testLoginUnnormal(){
Boolean ret = login("jklsfjkl", "asjkldjl' or '1=1");
// select * from user where username = 'jklsfjkl' and password = 'asjkldjl' or '1=1';
System.out.println("ret:" + ret);
}
}
解决办法: 使用 connection.prepareStatement(); 来解决这个安全隐患的问题
prepareStatement
提供了几个API
@Test
public void testPrepareStatementQuestion() throws SQLException {
// Statement statement = connection.createStatement();
// ? 表示占位符
// 这一句话,会对我们的sql语句去进行预编译,后续我们只需要把 ?填充进来即可,填充进来的都是值,不会是我们的关键字
PreparedStatement pst = connection.prepareStatement("select * from user where username = ? and password = ?");
pst.setString(1,"l");
pst.setString(2,"'l' or 1=1 ");
// 执行sql语句,获取结果
ResultSet resultSet = pst.executeQuery();
while(resultSet.next()) {
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String gender = resultSet.getString("gender");
int id = resultSet.getInt("id");
System.out.println("id : " + id + ", username : " + username + ", password:" + password + ", gender:" + gender);
}
}
// 结论,我们通过执行测试,发现并没有找到对应的用户,说明我们这里通过这种预编译占位的方式,可以解决数据库的注入问题
基本使用:和statement很类似。只是需要去占位
批处理
statement的批处理
Module复制步骤
- 第一步,点击需要复制的module
- 第二步,复制文件,删除.iml文件和targert文件
-
选中我们需要导入的pom文件
-
点击next 和finish 就可以了
-
检查项目的各个路径是否正确,例如java目录有没有被识别为source目录,resources目录有没有被识别为resources目录
这样就导入成功了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181125.html