package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo3_Connection {
public static void main(String[] args) throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql1 = "update account set money = 3000 where id = 1";
String sql2 = "update account set money = 3000 where id = 2";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
try {
// ============开启事务==========
conn.setAutoCommit(false);
//5. 执行sql
int count1 = stmt.executeUpdate(sql1);//受影响的行数
//6. 处理结果
System.out.println(count1);
//int i = 3/0; //制造异常
//5. 执行sql
int count2 = stmt.executeUpdate(sql2);//受影响的行数
//6. 处理结果
System.out.println(count2);
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需求提交事务
conn.commit();
} catch (Exception e) {
conn.rollback();
e.printStackTrace();
}
//7. 释放资源
stmt.close();
conn.close();
}
}
3.3 Statement
DDL与DML的区别
DML(Data Manipulation Language)数据操纵语言:
适用范围:对数据库中的数据进行一些简单操作,如insert,delete,update,select等.
DDL(Data Definition Language)数据定义语言:
适用范围:对数据库中的某些对象(例如,database,table)进行管理,如Create,Alter和Drop.
一、DDL(数据定义语言,Data Definition Language)
建库、建表、设置约束等:create\drop\alter
二、DML (数据操纵语言,Data Manipulation Language )
主要指数据的增删查改: Select\delete\update\insert\call
3.3.1 概述
Statement
对象的作用就是用来执行
SQL
语句。而针对不同类型的
SQL
语句使用的方法也不一样。
执行
DDL
、
DML
语句
执行DQL语句
该方法涉及到了
ResultSet
对象,而这个对象我们还没有学
习,重点讲解。
package com.itheima.jdbc;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* JDBC API 详解:Statement
*/
public class JDBCDemo4_Statement {
/**
* 执行DML语句
* @throws Exception
*/
@Test
public void testDML() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "update account set money = 3000 where id = 1";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句,受影响的行数
//6. 处理结果
//System.out.println(count);
if(count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
//7. 释放资源
stmt.close();
conn.close();
}
/**
* 执行DDL语句
* @throws Exception
*/
@Test
public void testDDL() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "create database db2";
// String sql = "drop database db2";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql);//执行完DDL语句,可能是0
//6. 处理结果
//System.out.println(count);
/* if(count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}*/
System.out.println(count);
//7. 释放资源
stmt.close();
conn.close();
}
}
注意:
以后开发很少使用java代码操作DDL语句
3.4 ResultSet
3.4.1 概述
ResultSet(结果集对象)作用:
==
封装了
SQL
查询语句的结果。
而执行了
DQL
语句后就会返回该对象,对应执行
DQL
语句的方法如
下:
ResultSet executeQuery(sql)
:执行
DQL
语句,返回
ResultSet
对象
那么我们就需要从
ResultSet
对象中获取我们想要的数据。
ResultSet
对象提供了操作查询结果数据的方法,如下
如下图为执行SQL语句后的结果
一开始光标指定于第一行前,如图所示红色箭头指向于表头行。当
我们调用了
next()
方法后,光标就下移到第一行数据,并且方法
返回
true
,此时就可以通过
getInt("id")
获取当前行
id
字段的
值,也可以通过
getString("name")
获取当前行
name
字段的
值。如果想获取下一行的数据,继续调用
next()
方法,以此类
推。
3.4.2 代码实现
package com.itheima.jdbc;
import org.junit.Test;
import java.sql.*;
/**
* JDBC API 详解:Statement
*/
public class JDBCDemo5_ResultSet {
/**
* 执行DQL
*
* @throws Exception
*/
@Test
public void testResultSet() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "select * from account";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果, 遍历rs中的所有数据
/* // 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
//6.2 获取数据 getXxx()
int id = rs.getInt(1);
String name = rs.getString(2);
double money = rs.getDouble(3);
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------");
}*/
// 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()) {
//6.2 获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id);
System.out.println(name);
System.out.println(money);
System.out.println("--------------");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
3.5 案例
需求:查询
account
账户表数据,封装为
Account
对象中,并且
存储到
ArrayList
集合中
package com.itheima.jdbc;
import com.itheima.pojo.Account;
import org.junit.Test;
import javax.swing.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* JDBC API 详解:Statement
*/
public class JDBCDemo5_ResultSet {
// /**
// * 执行DQL
// *
// * @throws Exception
// */
// @Test
// public void testResultSet() throws Exception {
// //1. 注册驱动
// //Class.forName("com.mysql.jdbc.Driver");
// //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
// String url = "jdbc:mysql:///db1?useSSL=false";
// String username = "root";
// String password = "1234";
// Connection conn = DriverManager.getConnection(url, username, password);
// //3. 定义sql
// String sql = "select * from account";
// //4. 获取statement对象
// Statement stmt = conn.createStatement();
// //5. 执行sql
// ResultSet rs = stmt.executeQuery(sql);
// //6. 处理结果, 遍历rs中的所有数据
// /* // 6.1 光标向下移动一行,并且判断当前行是否有数据
// while (rs.next()){
// //6.2 获取数据 getXxx()
// int id = rs.getInt(1);
// String name = rs.getString(2);
// double money = rs.getDouble(3);
//
// System.out.println(id);
// System.out.println(name);
// System.out.println(money);
//
// System.out.println("--------------");
//
// }*/
// // 6.1 光标向下移动一行,并且判断当前行是否有数据
// while (rs.next()) {
// //6.2 获取数据 getXxx()
// int id = rs.getInt("id");
// String name = rs.getString("name");
// double money = rs.getDouble("money");
//
// System.out.println(id);
// System.out.println(name);
// System.out.println(money);
//
// System.out.println("--------------");
// }
//
// //7. 释放资源
// rs.close();
// stmt.close();
// conn.close();
// }
/**
* 需求:查询account账户表数据,封装为Account对象中,并且
* 存储到ArrayList集合中
* 1. 定义实体类Account
* 2. 查询数据,封装到Account对象中
* 3. 将Account对象存入ArrayList集合中
*
* @throws Exception
*/
@Test
public void testResultSet2() throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "select * from account";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 创建集合(写在里面每次循环都会重置,浪费内存)
List<Account> list=new ArrayList<>();
// 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()) {
Account account = new Account();
//6.2 获取数据 getXxx()
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
//赋值
account.setId(id);
account.setName(name);
account.setMoney(money);
//存入方法
list.add(account);
}
System.out.println(list);
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
3.6 PreparedStatement
PreparedStatement
作用:
预编译
SQL
语句并执行:预防
SQL
注入问题
对上面的作用中
SQL
注入问题大家肯定不理解。那我们先对
SQL
注
入进行说明
.
3.6.1 SQL注入
SQL
注入是通过操作输入来修改事先定义好的
SQL
语句,用以达
到执行代码对服务器进行攻击的方法。
package com.itheima.jdbc;
import com.itheima.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 用户登录
*/
public class JDBCDemo6_UserLogin {
@Test
public void testLogin() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "123";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
/**
* 演示SQL注入
* @throws Exception
*/
@Test
public void testLogin_Inject() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "hfkjsfhskj";
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
System.out.println(sql);
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
上面代码是将用户名和密码拼接到
sql
语句中,拼接后的
sql
语句如
下
select
*
from
tb_user
where
username =
'sjdljfld'
and
password =
''
or
'1'
=
'1'
从上面语句可以看出条件
username = 'sjdljfld' and
password = ''
不管是否满足,而
or
后面的
'1' = '1'
是始终
满足的,最终条件是成立的,就可以正常的进行登陆了。
接下来我们来学习
PreparedStatement
对象
3.6.3 PreparedStatement概述
package com.itheima.jdbc;
import org.junit.Test;
import java.sql.*;
import java.util.Date;
/**
* API详解:PreparedStatement
*/
public class JDBCDemo7_PreparedStatement {
@Test
public void testPreparedStatement() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "123";
// 定义sql
String sql = "select * from tb_user where username = ? and password = ?";
// 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1, name);
pstmt.setString(2, pwd);
// 执行sql
ResultSet rs = pstmt.executeQuery();
// 判断登录是否成功
if (rs.next()) {
System.out.println("登录成功~");
} else {
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
pstmt.close();
conn.close();
}
/**
* PreparedStatement原理
*
* @throws Exception
*/
@Test
public void testPreparedStatement2() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
// useServerPrepStmts=true 参数开启预编译功能
String url = "jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "' or '1' = '1";
// 定义sql
String sql = "select * from tb_user where username = ? and password = ?";
// 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
Thread.sleep(10000);
// 设置?的值
pstmt.setString(1, name);
pstmt.setString(2, pwd);
ResultSet rs = null;
// 执行sql
rs = pstmt.executeQuery();
// 设置?的值
pstmt.setString(1, "aaa");
pstmt.setString(2, "bbb");
// 执行sql
rs = pstmt.executeQuery();
// 判断登录是否成功
if (rs.next()) {
System.out.println("登录成功~");
} else {
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
pstmt.close();
conn.close();
}
}
3.6.4 使用PreparedStatement改进(跳过)
4.2 数据库连接池实现
4.3 Driud使用
* Druid数据库连接池演示
*/
public class DruidDemo {
public static void main(String[] args) throws
Exception {
//1.导入jar包
//2.定义配置文件
//3. 加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbcdemo/src/druid.properties"));
//4. 获取连接池对象
DataSource dataSource =
DruidDataSourceFactory.createDataSource(prop);
//5. 获取数据库连接 Connection
Connection connection =
dataSource.getConnection();
System.out.println(connection); //获取到了连接
后就可以继续做其他操作了
//System.out.println(System.getProperty("user.dir")
);
}
}