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
语句
![](https://img-blog.csdnimg.cn/99cf154fc277418881c2762b49212880.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a6BbXk=,size_20,color_FFFFFF,t_70,g_se,x_16)
执行DQL语句
![](https://img-blog.csdnimg.cn/86b56fa71e0d4e1d891a9f726018478e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a6BbXk=,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/cc49065a413347bcbde3b5dacaf15cec.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a6BbXk=,size_20,color_FFFFFF,t_70,g_se,x_16)
该方法涉及到了
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语句后的结果
![](https://img-blog.csdnimg.cn/b58912ec4b2848c78ff71607e058339e.png)
一开始光标指定于第一行前,如图所示红色箭头指向于表头行。当
我们调用了
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使用
![](https://img-blog.csdnimg.cn/ec11c3e140394c58b320496630abc062.png)
* 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")
);
}
}