前言
将最近学习的JDBC编程整理成笔记,做次记录。
mysql 安装
首先安装mysql 8.0.19 版本数据库。
下载地址 https://downloads.mysql.com/archives/community/
下载完成后点击默认安装即可。
默认安装到了C:\Program Files\MySQL\MySQL Server 8.0\bin
目录下。
关于mysql的一些命令:
mysqld.exe --initialize-insecure 初始化数据库,执行后会生成data文件夹
mysqld.exe --install 安装mysql服务
net start mysql 启动mysql服务
set password for root@localhost = password('password'); 修改密码
flush privileges 刷新权限
JDBC 简介
JDBC全称是Java DataBase Connectivity的缩写,是Java程序访问数据库的标准接口。
使用java里面提供的一些类和方法,利用程序链接数据库,进行增删改查,这个过程叫JDBC编程。
要实现JDBC编程,除了java.sql标准库,还需要找一个MySQL的JDBC驱动。其实就是一个第三方jar包。
这里下载mysql-connector-java-8.0.23 版本的jar包。 https://dev.mysql.com/downloads/connector/j/
下载后在eclipse 引入jar包。
并添加到项目库。
JDBC 编程
JDBC编程主要分为六步操作:
- 加载驱动程序
- 连接数据库
- 获取数据库操作对象
- 执行sql语句
- 处理查询结果集
- 释放连接
举个栗子:
实现最简单的查询语句
package jdbc_test;
import java.sql.*;
public class jdbcdemo01 {
/**
*
* @param username
* @param password
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");//加载驱动
String url = "jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true";
String user = "root";
String pass = "";
conn = DriverManager.getConnection(url,user,pass);//获取连接
stmt = conn.createStatement();//获取数据库操作对象
String sql = "select * from user";
rs = stmt.executeQuery(sql);//执行sql语句
while(rs.next()) {
System.out.print(rs.getInt(1)+","+rs.getString("username")+","+rs.getString(3)+","+rs.getString(4));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
rs.close();
stmt.close();
conn.close();
}
}
}
注意:url地址的完整度,执行查询语句用的是executeQuery方法,以及驱动连接用的是Class.forName()
还有一种方式也可以实现。
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());// 第二种
但new com.mysql.cj.jdbc.Driver()
创建对象的时候本质上也执行了DriverManager.registerDriver(driver)
,这样一来就重复了,所以我们更习惯使用Class.forName()
。
第二个例子,更新语句
package jdbc_test;
import java.sql.*;
public class jdbcdemo01 {
/**
*
* @param username
* @param password
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
Connection conn=null;
Statement stmt=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");//加载驱动
String url = "jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true";
String user = "root";
String pass = "";
conn = DriverManager.getConnection(url,user,pass);//获取连接
stmt = conn.createStatement();//获取数据库操作对象
String sql = "update user set loginpwd=123456789 where id=1";
int count = stmt.executeUpdate(sql);//执行sql语句
System.out.println(count == 1 ? "更新成功" : "更新失败");
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
stmt.close();
conn.close();
}
}
}
注意:更新方法用的是executeUpdate,包括插入、删除、更新,并返回一个int值,所以自然也没有查询记过集
区分一下这两个方法。
int executeUpdate(insert/delete/update)
Resultset executeQuery(select)
PreparedStatement 对象
在了解PreparedStatement对象之前,先设计一个登录的demo,并尝试一种工具类提取的方式编写代码。
首先新建db.properties文件,提取出连接数据库的信息。
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true
username=root
password=
再提取出jdbc连接工具类JdbcUtils.java
package jdbc_test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;
// 提取工具类
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
try {
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 加载驱动
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
// 释放连接资源
public static void release(Connection conn,Statement st,ResultSet rs) {
if(rs!=null) {try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}}
if(st!=null) {try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}}
if(conn!=null) {try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}}
}
}
最后再编写jdbcDemo3.java,来实现用户登录。
jdbcDemo3.java
package jdbc_test;
import java.sql.*;
import java.util.*;
public class jdbcdemo3 {
public static void main(String[] args) {
Map userlogininfo = loginit();
String loginName = (String) userlogininfo.get("username");
String loginPwd = (String) userlogininfo.get("password");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
String sql = "select * from user where loginName='"+loginName+"' and loginPwd='"+loginPwd+"' ";
rs = stmt.executeQuery(sql);
if(rs.next()) {
System.out.print("login success");
}else {
System.out.print("login false");
}
}catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn, stmt, rs);
}
}
private static Map loginit() {
Scanner s = new Scanner(System.in);
System.out.print("username:");
String username = s.nextLine();
System.out.print("password:");
String password = s.nextLine();
Map userlogininfo = new HashMap();
userlogininfo.put("username",username);
userlogininfo.put("password",password);
return userlogininfo;
}
}
尝试登录。
但是该编写方式存在sql注入问题,当用户输入特殊的用户名、密码时,也可以登录成功。
如a' or 1='1
这是因为真值 or 真值 and 假值 or 真值,结果即为真值。会查询出所有结果。
那么该如何解决sql注入的问题呢?这就有了PreparedStatement 对象。
该对象用来防止sql注入,是Statement的子类,可对sql进行预编译,从而提高数据库的执行效率。
修改jdbcDemo3.java
package jdbc_test;
import java.sql.*;
import java.util.*;
public class jdbcdemo3 {
public static void main(String[] args) {
Map userlogininfo = loginit();
String loginName = (String) userlogininfo.get("username");
String loginPwd = (String) userlogininfo.get("password");
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from user where loginName = ? and loginPwd= ? ";
//?代表占位符,不能使用单引号括起来
stmt = conn.prepareStatement(sql);//sql语句的预先编译
//再给占位符传值,即使再注入,sql语句也没有编译
stmt.setString(1, loginName);
stmt.setString(2, loginPwd);
rs = stmt.executeQuery();//执行sql语句
if(rs.next()) {
System.out.print("login success");
}else {
System.out.print("login false");
}
}catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn, stmt, rs);
}
}
private static Map loginit() {
Scanner s = new Scanner(System.in);
System.out.print("username:");
String username = s.nextLine();
System.out.print("password:");
String password = s.nextLine();
Map userlogininfo = new HashMap();
userlogininfo.put("username",username);
userlogininfo.put("password",password);
return userlogininfo;
}
}
注意:无法sql注入就是因为PreparedStatement 对象在执行sql语句时先进行了预编译
总结
学习了JDBC的基本过程,复习了db.properties文件、代码层的sql注入,蛮有收获,继续加油。