java基础知识——JDBC(重点)
前言:
本人在学习jdbc知识之时,觉得学的懵懵懂懂,踩了很多坑,为了避免犯我同样的错误,我给大家分享一下如何快速学懂jdbc的技巧,要想通俗易懂的学习并掌握jdbc,我们需要先了解数据库驱动,掌握数据库的基本使用和对链表的一些基本理解
1.数据库驱动:
数据库驱动程序:是一个动态链接库(DLL),用以将特定的开放式数据库连接的数据源和另一度个应用程序(客户端)相连接。但这样应用的话,每个应用都需要添加对应的驱动,才能连接到对应的数据库,需要用不同的数据库,就要不断的添加数据库驱动,导致很不方便.jdbc就能解决这个问题.
2.JDBC介绍
JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现,本文中的代码都是针对MySQL数据库实现的。
3.jdbc实现详细步骤
1.准备工作:
- mysql-connector-java-5.0.8-bin.jar包(访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个.Jar的文件里),推荐去MAVEN下载:https://mvnrepository.com
- 通过可视化工具打开数据库,创建一个新的数据库并添加数据:操作命令如下:
-- 创建一个新的数据库
CREATE DATABASE jdbcstudy CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 切换到当前新建的数据库
USE jdbcstudy;
-- 在当前数据库中建一张表
CREATE TABLE users(
`id` INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
`email` VARCHAR(60),
`birthday` DATE
)
-- 在新建表格中添加数据
INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(1,'zhangsan','123456','zs@sina.com','1998-08-08')
,(2,'lisi','123456','lisi@sina.com','1999-09-09'),(3,'wanger','123456','wanger@sina.com','2000-01-01');
2.创建一个普通java项目,并建立一个lib文件夹(和src目录同级),导入数据库驱动,将mysql-connector-java-5.0.8-bin.jar放到lib文件夹中,mysql-connector-java-5.0.8-bin.ja右击,点击Add as Libary,将其添加到项目库中,才可以使用
3.项目一切准备就绪,如下图:
4.书写第一个jdbc代码
package com.mage;
import java.sql.*;
/**
* @param
* @author qzp
* @create 2020-04-10 15:22
*/
//我的第一个jdbc程序
public class Myfristjdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动(固定写法)
Class.forName("com.mysql.jdbc.Driver");
//2.用户信息和url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";//根据自己的数据库用户名来填写
String password = "root";//根据自己的数据库密码来填写,没有密码就用""
//3.与数据库进行连接,返回数据库对象Connection
Connection conn = DriverManager.getConnection(url, username, password);
//4.创建执行sql语句的对象Statement
Statement statement = conn.createStatement();
//5.书写sql语句
String sql = "select * from users";
//6.执行sql语句,可能存在返回结果或影响行数
ResultSet resultSet = statement.executeQuery(sql);
//7.打印结果
while (resultSet.next()){
System.out.println("id:"+resultSet.getObject("id"));
System.out.println("name:"+resultSet.getObject("name"));
System.out.println("password:"+resultSet.getObject("password"));
System.out.println("email:"+resultSet.getObject("email"));
System.out.println("birthday:"+resultSet.getObject("birthday"));
System.out.println("------------------------------------------------");
}
//8.释放连接
resultSet.close();
statement.close();
conn.close();
}
}
一看上述代码,感觉不多,但发现有很多点想不通,也不好记,死记硬背,不是上上计策,如果你能把上述代码和可视化工具(例如:navicate)连接数据库开始的界面对应起来,联想到可视化工具如何执行sql语句并展示结果,你就能很快理解并掌握上述代码的书写
4.分析上述代码
DriverManager
//方式一:注册驱动并加载驱动(不推荐使用)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//方式二:加载驱动(固定写法)
Class.forName("com.mysql.jdbc.Driver");
i.这两者方式的区别?分析:打开com.mysql.jdbc.Driver的源码中,有一个static静态代码块,这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作,对于DriverManager.registerDriver(new Driver()); 多new一个Driver浪费;而Class.forName(“com.mysql.jdbc.Driver”); 就可以搞定一切.对于反射使用,
ii.为什么不获取反射的对象,因为我们不需要使用反射的对象
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
分析如下:
//mysql默认的端口:3306
//jdbc:mysql://主机名:端口/数据库名称?参数1&参数2
//oracle默认端口:1521
//jdbc:oracle:thin:@localhost:1521:sid
useUnicode=true&characterEncoding=UTF-8&useSSL=true
- 添加的作用是:指定字符的编码、解码格式。
分析如下:
例如:mysql数据库用的是gbk编码,而项目数据库用的是utf-8编码。这时候如果添加了useUnicode=true&characterEncoding=UTF-8 ,那么作用有如下两个方面:
-
存数据时:数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。
-
取数据时:在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端。
-
useSSL=true建立安全连接
Connection
//3.与数据库进行连接,返回数据库对象Connection
Connection conn = DriverManager.getConnection(url, username, password);
分析如下:
//conn代表数据库,可以对数据库数据进行管理
conn.rollback();//事务的回滚
conn.commit();//事务的提交
conn.setAutoCommit(true);//设置数据库自动提交
Statement
//4.创建执行sql语句的对象Statement
Statement statement = conn.createStatement();
分析如下:
//执行sql语句的对象Statement
String sql = "select * from users";
statement.execute(sql);//执行任何sql
statement.executeQuery(sql);//执行查询操作返回ResultSet
statement.executeUpdate(sql);//执行更新、插入、删除,返回一个受影响行
注意:PreparedStatement和Statement都是执行sql对象,PreparedStatement后面会说明
ResultSet 查询结果集,封装了所有的查询结果
//6.执行sql语句,可能存在返回结果或影响行数
ResultSet resultSet = statement.executeQuery(sql);
分析如下:
//获取指定的数据类型
resultSet.getObject();//--在不知道列类型的情况下使用
resultSet.getInt();//--对应列属性数值int
resultSet.getString();//--对应列属性字符串varchar
resultSet.getDate();//--对应列属性时间日期
resultSet.getFloat();//--对应列属性float
//遍历,指针
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后
resultSet.next();//移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
释放资源:内存开销大,一定要关闭
//8.释放连接
resultSet.close();
statement.close();
conn.close();
5.Statement对象
jdbc中的Statement对象用于向数据库发送SQL语句,完成对数据库的增删查改
- Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate方法执行完毕后,将会返回一个整数(即增删改语句导致数据库中的数据发生变化的记录总数)
- Statement对象的executeQuery方法,用于向数据库发送查sql语句,executeQuery方法执行完毕后,返回查询结果集ResultSet对象
6.CURD操作
create
使用executeUpdate(String sql)方法完成对数据的添加操作,实例如下:
Statement statement = conn.createStatement();
String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(1,'zhangsan','123456','zs@sina.com','1998-08-08')";
int row = statement.executeUpdate(sql);
if(row > 0){
System.out.println("插入成功!");
}
update
使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:
Statement statement = conn.createStatement();
String sql = "update users set name="qzp" where id = 1;
int row = statement.executeUpdate(sql);
if(row > 0){
System.out.println("更新成功!");
}
delete
使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:
Statement statement = conn.createStatement();
String sql = "delete from users where id = 1";
int row = statement.executeUpdate(sql);
if(row > 0){
System.out.println("删除成功!");
}
read
使用executeUpdate(String sql)方法完成对数据的删除操作,实例如下:
Statement statement = conn.createStatement();
String sql = "select * from users";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("id:"+resultSet.getObject("id"));
System.out.println("name:"+resultSet.getObject("name"));
System.out.println("password:"+resultSet.getObject("password"));
System.out.println("email:"+resultSet.getObject("email"));
System.out.println("birthday:"+resultSet.getObject("birthday"));
}
7.代码封装
在src目录下创建,db.properties配置文件,目的:方便下次调试使用不同的数据库
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=UTF-8&useSSL=true
username=root
password=root
封装增删查改需要重复写的代码,将其封场成为一个工具类,方便下次调用
因为在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候直接调用即可:
package com.mage.util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @param
* @author qzp
* @create 2020-04-10 20:57
*/
@SuppressWarnings("all")
public class Jdbcutils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
InputStream in = jdbcutils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//1.加载驱动且加一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//2.获取连接
public static Connection getconnection(){
try {
return DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
//释放连接资源,先开后关
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();
}
}
}
}
8.测试工具类
引用工具类实现插入数据:
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import javax.lang.model.element.VariableElement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @param
* @author qzp
* @create 2020-04-10 21:30
*/
public class Myjdbcutilstest {
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
conn = Jdbcutils.getconnection();
statement = conn.createStatement();
String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(4,'wjw','123456','wjw@sina.com','1998-06-12')";
int i = statement.executeUpdate(sql);
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, statement, null);
}
}
}
9.SQL注入问题
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息
模拟登录,呈现SQL注入问题
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @param
* @author qzp
* @create 2020-04-10 21:58
*/
//模拟登录,呈现SQL注入问题
@SuppressWarnings("all")
public class SqlTest {
public static void main(String[] args) {
//正常登录
login("qzp", "123456");
//SQL注入
login("' or '1=1 ", "123456");
login("' or '1=1 ", " ' or '1=1");
}
public static void login(String name,String password){
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
conn = Jdbcutils.getconnection();
statement = conn.createStatement();
//SELECT * from users WHERE `name` = 'qzp' AND `password` = '123456';--正常查询
//SELECT * from users WHERE `name` = '' or '1=1' AND `password` = '123456';--SQL注入
//SELECT * from users WHERE `name` = '' or '1=1' AND `password` = '' or '1=1';--SQL注入
String sql = "SELECT * from users WHERE `name` = '"+name+"' AND `password` = '"+password+"'";
resultSet = statement.executeQuery(sql);
//7.打印结果
while (resultSet.next()){
System.out.println("id:"+resultSet.getInt("id"));
System.out.println("name:"+resultSet.getString("name"));
System.out.println("password:"+resultSet.getObject("password"));
System.out.println("email:"+resultSet.getObject("email"));
System.out.println("birthday:"+resultSet.getObject("birthday"));
System.out.println("------------------------------------------------");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, statement, resultSet);
}
}
}
10.PreparedStatement对象
代码实现CRUD:
create
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.*;
import java.util.Date;
/**
* @param
* @author qzp
* @create 2020-04-10 22:27
*/
public class PreparedStatementTest {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement preparedStatement = null;
try {
conn = Jdbcutils.getconnection();
//String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(4,'wjw','123456','wjw@sina.com','1998-06-12')";
//使用? 占位符代替参数
String sql = "INSERT into users(`id`,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
//预编译sql,先书写sql,但不执行
preparedStatement = conn.prepareStatement(sql);
//手动给每个参数赋值
preparedStatement.setInt(1,4);
preparedStatement.setString(2, "wjw");
preparedStatement.setInt(3, 123456);
preparedStatement.setString(4, "wjw@sina.com");
//注意点: java.sql.Date:数据库
// java.util.Date:java
preparedStatement.setDate(5, new java.sql.Date(new Date().getTime()));
//执行sql
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, preparedStatement, null);
}
}
}
update
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @param
* @author qzp
* @create 2020-04-10 22:27
*/
public class PreparedStatementTest3 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement preparedStatement = null;
try {
conn = Jdbcutils.getconnection();
//使用? 占位符代替参数
String sql = "update users set name=? where id = ?";
//预编译sql,先书写sql,但不执行
preparedStatement = conn.prepareStatement(sql);
//手动给每个参数赋值
preparedStatement.setString(1,"王佳雯");
preparedStatement.setInt(2,4);
//执行sql
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("更新成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, preparedStatement, null);
}
}
}
delete
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
/**
* @param
* @author qzp
* @create 2020-04-10 22:27
*/
public class PreparedStatementTest2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement preparedStatement = null;
try {
conn = Jdbcutils.getconnection();
//使用? 占位符代替参数
String sql = "delete from users where id = ?";
//预编译sql,先书写sql,但不执行
preparedStatement = conn.prepareStatement(sql);
//手动给每个参数赋值
preparedStatement.setInt(1,4);
//执行sql
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, preparedStatement, null);
}
}
}
read
package com.mage.jdbc;
import com.mage.util.Jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* @param
* @author qzp
* @create 2020-04-10 22:27
*/
public class PreparedStatementTest4 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
conn = Jdbcutils.getconnection();
//使用? 占位符代替参数
String sql = "select * from users where id = ?";
//预编译sql,先书写sql,但不执行
preparedStatement = conn.prepareStatement(sql);
//手动给每个参数赋值
preparedStatement.setInt(1,4);
//执行sql
resultSet = preparedStatement.executeQuery();
//获取查询出的结果
while (resultSet.next()){
System.out.println("id:"+resultSet.getInt("id"));
System.out.println("name:"+resultSet.getString("name"));
System.out.println("password:"+resultSet.getObject("password"));
System.out.println("email:"+resultSet.getObject("email"));
System.out.println("birthday:"+resultSet.getObject("birthday"));
System.out.println("------------------------------------------------");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
Jdbcutils.close(conn, preparedStatement, resultSet);
}
}
}
注意:
PreparedStatement是继承Statement,所以封装好的代码可以不用改动!!!!!!
PreparedStatement可以防止SQL注入,效率比Statement高
本片文章就分享到这里,如果文章中有小问题或者你有什么疑问,欢迎大家在评论区留言提出类,我会及时给大家提供解决方法,谢谢!