JDBC
添加驱动
根据MySQL的版本添加
JDBC的六步连接
// 数据库的六步连接
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1、注册驱动
// mysql 8.0以上
Class.forName("com.mysql.cj.jdbc.Driver");
// mysql 8.0以下
//Class.forName("com.mysql.jdbc.Driver");
// oracle数据库
//Class.forName("oracle.jdbc.driver.OracleDriver");
// 2、获取连接
System.out.println("连接数据库。。。");
// Oracle数据库连接地址:oracle:jdbc:thin:@localhost:1521:数据库名
// MySQL数据库连接地址:jdbc:mysql://localhost:3306/数据库名
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名", "root", "数据库密码");
System.out.println("conn : " + conn);
// 3、获取数据库操作对象
stmt = conn.createStatement();
// 4、执行sql语句
String sql = "sql语句";
rs = stmt.executeQuery(sql);
// 5、处理结果集——循环遍历
// for——我已经知道循环的次数
// while——不知道循环的次数
while (rs.next()) {
// 通过字段检索
// 例如:int id = rs.getInt("id");
// String name = rs.getString("name"); // 不管数据库中是什么类型,统一以String形式返回
// 输出数据
// 例如:System.out.println(id + "," + name);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6、释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC的六步连接(使用配置文件的方式)
db.properties
# mysql连接信息
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名
user=root
password=数据库密码
# oracle连接信息
#driver=oracle.jdbc.driver.OracleDriver
#url=oracle:jdbc:thin:@localhost:1521:数据库名
#user=数据库用户名
#password=数据库密码
// 资源绑定器
ResourceBundle bundle = ResourceBundle.getBundle("resources/db");
// 通过属性配置文件拿到信息
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
// 数据库的六步连接
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1、注册驱动
Class.forName(driver);
// 2、获取连接
System.out.println("连接数据库。。。");
conn = DriverManager.getConnection(url, user, password);
System.out.println("conn : " + conn);
// 3、获取数据库操作对象
stmt = conn.createStatement();
// 4、执行sql语句
String sql = "sql语句";
rs = stmt.executeQuery(sql);
// 5、处理结果集——循环遍历
// for——我已经知道循环的次数
// while——不知道循环的次数
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6、释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
防止sql注入攻击
t_user.sql
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`role` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `t_user` VALUES ('1', 'admin', '123', '管理员');
INSERT INTO `t_user` VALUES ('2', 'user', '123', '普通用户');
登录注册代码
public class JdbcTest01 {
public static void main(String[] args) {
// 初始化界面
HashMap<String, String> loginInfo = login();
// 连接数据库验证账号密码
boolean result = checkNameAndPwd(loginInfo.get("loginName"),loginInfo.get("loginPwd"));
System.out.println(result ? "登录成功" : "登录失败");
}
/**
* 验证用户名和密码
* @param loginName 登录名
* @param loginPwd 密码
* @return true表示登录成功,false表示登录失败
*/
private static boolean checkNameAndPwd(String loginName, String loginPwd) {
boolean result = false;
// 数据库的六步连接
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
System.out.println("连接数据库。。。");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest", "root", "123456");
System.out.println("conn : " + conn);
// 3、获取数据库操作对象
stmt = conn.createStatement();
// 4、执行sql语句
String sql = "select * from t_user where username = '" + loginName + "' and password = '" + loginPwd + "'";
System.out.println(sql);
rs = stmt.executeQuery(sql);
// 5、处理结果集
if (rs.next()) {
result = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6、释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return result;
}
/**
* 初始化界面,提供用户输入
* @return 返回存储登录用户名和密码的集合
*/
private static HashMap<String, String> login() {
System.out.println("欢迎使用该系统,请输入用户名和密码进行身份认证");
Scanner scanner = new Scanner(System.in);
System.out.print("用户名:");
String loginName = scanner.next();
System.out.print("密码:");
String loginPwd = scanner.next();
// 将用户名和密码放到Map集合中
HashMap<String, String> loginInfo = new HashMap<>();
loginInfo.put("loginName",loginName);
loginInfo.put("loginPwd",loginPwd);
// 返回Map
return loginInfo;
}
}
正常登录
sql注入攻击
导致SQL注入的根本原因:先进行了字符串的拼接,再进行的编译
。用户输入的用户名信息以及密码信息中含有sql语句的关键词,这个关键词与底层的sql语句进行“字符串拼接”,导致原sql语句的含义被扭曲。
最主要的原因是:用户提供的信息参与了sql语句的编译。
防止sql注入
// Statement stmt = null;
// 改成
PreparedStatement stmt = null;
// 把第三、四步改为以下代码
// 防止SQL注入
String sql = "select * from t_user where username = ? and password = ?";
// prepareStatement 预编译的数据库操作对象
stmt = conn.prepareStatement(sql);
stmt.setString(1,loginName);
stmt.setString(2,loginPwd);
rs = stmt.executeQuery();
sql注入失败
java.sql.Statement接口的特点:先进行字符串的拼接,然后再进行sql语句的编译。
- 优点:使用Statement可以进行sql语句的拼接。
- 缺点,因为拼接的存在,导致了sql注入。
java.sql.PreparedStatement接口的特点:先进行sql语句的编译,然后再进行sql语句的传值。 - 优点:防止了sql注入。
- 缺点:无法进行sql语句的拼接,只能传值。
模糊查询
要把整个条件当作一个问号
String sql = "select * from t_user where username like ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1,"%u%");
rs = stmt.executeQuery();
JDBC事务
conn.setAutoCommit(false);
// 关闭自动提交机制
conn.commit();
// 手动提交
conn.rollback();
// 手动回滚
DROP TABLE IF EXISTS `t_act`;
CREATE TABLE `t_act` (
`actno` char(1) PRIMARY KEY,
`balance` double(10,2)
);
INSERT INTO `t_act` VALUES ('A', '20000.00');
INSERT INTO `t_act` VALUES ('B', '0.00');
/*
JDBC事务:
conn.setAutoCommit(false); // 关闭自动提交机制
conn.commit(); // 手动提交
conn.rollback();// 手动回滚
*/
public class JdbcTest02 {
public static void main(String[] args) {
// 数据库的六步连接
Connection conn = null;
PreparedStatement ps = null;
try {
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest", "root", "123456");
// 开启事务,关闭自动提交机制
conn.setAutoCommit(false);
// 3、获取预编译的数据库操作对象
String sql = "update t_act set balance = ? where actno = ?";
ps = conn.prepareStatement(sql);
ps.setDouble(1,10000);
ps.setString(2,"A");
int count = ps.executeUpdate();
// 模拟异常
String s = null;
s.toString();
ps.setDouble(1,10000);
ps.setString(2,"B");
count += ps.executeUpdate();
System.out.println(count == 2 ? "转账成功" : "转账失败");
// 手动提交,事务结束
conn.commit();
} catch (Exception e) {
try {
// 出现异常,手动回滚
if (conn != null) conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
// 6、释放资源
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
JDBC工具类封装
JDBC工具类:
/*
JDBC工具类
*/
public class DBUtil {
// 工具类中的构造方法一般都是私有化的,为了防止new对象
// 工具类中的方法都是静态的,不需要new对象,直接使用“类名.”的方式调用
private DBUtil() {}
// 静态变量与静态代码块执行时间一致
// 类加载时绑定属性资源文件
private static ResourceBundle bundle = ResourceBundle.getBundle("resources/db");
// 注册驱动
static {
try {
Class.forName(bundle.getString("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* 释放资源
* @param conn 连接对象
* @param stmt 数据库操作对象
* @param rs 查询结果集
*/
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试DBUtil工具类:
/*
测试DBUtil工具类
*/
public class JdbcTest03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 获取连接
conn = DBUtil.getConnection();
// 获取预编译的数据库操作对象
String sql = "select * from t_user where username like ?";
ps = conn.prepareStatement(sql);
ps.setString(1,"a%");
// 执行sql
rs = ps.executeQuery();
// 处理结果集
while (rs.next()) {
System.out.println(rs.getString("username") + "," + rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 释放资源,没有的对象传null
DBUtil.close(conn, ps, rs);
}
}
}