一.JDBC简介
1.1JDBC概念
- JDBC就是使用Java语言操作关系型数据库的一套API
- 全称:(Java DataBase Connectivity) Java数据库连接
1.2JDBC本质
- 官方(sum)公司定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
1.3JDBC好处
- 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
- 可随时替换底层数据库,访问数据库的Java代码基本不变
二.JDBC快速入门
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC快速入门
* */
public class Demo1 {
public static void main(String[] args) throws Exception{
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");//反射
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/sql_base";
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//3.定义sql
String sql = "update account set money = 4000 where id = 1";
//4.获取sql执行对象
Statement statement = con.createStatement();
//5.执行sql
int count = statement.executeUpdate(sql);//返回值是受影响的条数
//6.处理返回结果
System.out.println(count);
//7.释放资源 注意释放的先后顺序 先开后释放
statement.close();
con.close();
}
}
此处使用的的MySQL数据库版本是mysql-5.7.30-winx64,驱动包是mysql-connector-java-8.0.29
三.JDBC的API详解
3.1DriverManager
作用:
- 注册驱动
- 获取数据库连接
获取连接方式
Connection con = DriverManager.getConnection(url,user,password);
/**
* url:连接路径
* 语法:jdbc:mysql//ip地址:端口号/数据库名称?参数键值对1&参数键值对2
* 细节:
* 如果连接的是本机mysql,并且mysql服务器默认端口号是3306,则可以简写 jdbc:mysql///数据库名称?参数键值对
* 配置useSSL=false参数,禁用安全连接方式,解决警告提示
*
* user:用户名
* password:密码
* */
3.2Connection
获取执行SQL对象
//4.获取sql执行对象
Statement statement = con.createStatement();
事务管理
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/**
* JDBC API详解 Connection
* */
public class Demo3_Connection {
public static void main(String[] args) throws Exception{
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");//反射 mysql5之后可以省略不写了
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/sql_base";
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//3.定义sql
String sql1 = "update account set money = 1000 where id = 1";
String sql2 = "update account set money = 1000 where id = 2";
//4.获取sql执行对象
Statement statement = con.createStatement();
try {
//开启事务
con.setAutoCommit(false);
//5.执行sql
int count1 = statement.executeUpdate(sql1);//返回值是受影响的条数
int count2 = statement.executeUpdate(sql2);//返回值是受影响的条数
//6.处理返回结果
System.out.println(count1);
System.out.println(count2);
//提交事务
con.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
con.rollback();
}
//7.释放资源 注意释放的先后顺序 先开后释放
statement.close();
con.close();
}
}
3.3Statement
package 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 Demo4_Statement {
/**
* 执行DML语句
* @throws SQLException
*/
@Test
public void testDML() throws SQLException {
//1.注册驱动
// Class.forName("com.mysql.cj.jdbc.Driver");//反射 mysql5之后可以省略不写了
//2.获取连接
String url = "jdbc:mysql:///sql_base?useSSL=false"; //本机服务器的ip和端口可以省略不写
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//3.定义sql
String sql = "update account set money = 4000 where id = 5";
//4.获取sql执行对象
Statement statement = con.createStatement();
//5.执行sql
int count = statement.executeUpdate(sql);//执行完DML语句后,受影响的行数
//6.处理返回结果
// System.out.println(count);
if(count > 0){
System.out.println("修改成功");
} else {
System.out.println("修改失败");
}
//7.释放资源 注意释放的先后顺序 先开后释放
statement.close();
con.close();
}
/**
* 执行DDL语句
* @throws SQLException
*/
@Test
public void testDDL() throws SQLException {
//1.注册驱动
// Class.forName("com.mysql.cj.jdbc.Driver");//反射 mysql5之后可以省略不写了
//2.获取连接
String url = "jdbc:mysql:///sql_base?useSSL=false"; //本机服务器的ip和端口可以省略不写
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//3.定义sql
String sql = "drop database db2";
//4.获取sql执行对象
Statement statement = con.createStatement();
//5.执行sql
int count = statement.executeUpdate(sql);//执行完DML语句后,受影响的行数
//6.处理返回结果
System.out.println(count);//成功执行完DDL,结果可能返回零
// if(count > 0){
// System.out.println("修改成功");
// } else {
// System.out.println("修改失败");
// }
//7.释放资源 注意释放的先后顺序 先开后释放
statement.close();
con.close();
}
}
注意 @Test 需要导入 import org.junit.Test;
3.4ResutlSet
package pojo;
public class Account {
private int id;
private String name;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
package jdbc;
import org.junit.Test;
import pojo.Account;
import java.sql.*;
import java.util.ArrayList;
/**
* JDBC API详解 ResultSet
*/
public class Demo5_ResultSet {
/**
* ResultSet
*
* @throws SQLException
*/
@Test
public void testResultSet() throws SQLException {
//1.注册驱动
// Class.forName("com.mysql.cj.jdbc.Driver");//反射 mysql5之后可以省略不写了
//2.获取连接
String url = "jdbc:mysql:///sql_base?useSSL=false"; //本机服务器的ip和端口可以省略不写
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url, user, password);
//3.定义sql
String sql = "select * from account";
//4.获取sql执行对象
Statement statement = con.createStatement();
//5.执行sql
// statement.executeUpdate("insert into account values (3,'王五',2000)");
ResultSet rs = statement.executeQuery(sql);
//6.处理数据
// while (rs.next()) {
// 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("---------------------------------");
//
// }
while (rs.next()) {
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();
statement.close();
con.close();
}
@Test
public void testResultSet2() throws SQLException {
//1.注册驱动
// Class.forName("com.mysql.cj.jdbc.Driver");//反射 mysql5之后可以省略不写了
//2.获取连接
String url = "jdbc:mysql:///sql_base?useSSL=false"; //本机服务器的ip和端口可以省略不写
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url, user, password);
//3.定义sql
String sql = "select * from account";
//4.获取sql执行对象
Statement statement = con.createStatement();
//5.执行sql
ResultSet rs = statement.executeQuery(sql);
//6.处理数据
ArrayList<Account> list = new ArrayList<>();
while (rs.next()) {
Account account = new Account();
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();
statement.close();
con.close();
}
}
3.5PreparedStatement
普通登录演示
/**
* 演示普通登录操作
* @throws SQLException
*/
@Test
public void testLogin() throws SQLException {
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/sql_base";
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//获取sql对象
Statement statement = con.createStatement();
//获得用户输入的账号和密码
String name = "张三";
String psw = "124";
//sql执行语句
String sql = "select * from user where name='"+name+"' and password='"+psw+"'";
ResultSet rs = statement.executeQuery(sql);
//处理数据
if(rs.next()){
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
//7.释放资源 注意释放的先后顺序 先开后释放
rs.close();
statement.close();
con.close();
}
SQL注入
/**
* 演示SQL注入
* @throws SQLException
*/
@Test
public void testLogin_Inject() throws SQLException {
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/sql_base";
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//获取sql对象
Statement statement = con.createStatement();
//获得用户输入的账号和密码
String name = "wslahlghh";
// String psw = "124";
String psw = "' or '1' = '1 ";
//sql执行语句
String sql = "select * from user where name='"+name+"' and password='"+psw+"'";
ResultSet rs = statement.executeQuery(sql);
//处理数据
if(rs.next()){
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
//7.释放资源 注意释放的先后顺序 先开后释放
rs.close();
statement.close();
con.close();
}
原因:
在sql字符串的拼接过程中 sql被修改了
select * from user where name='wslahlghh' and password='' or '1' = '1'
-- 被修改的sql语句where条件恒成立
PreparedStatement作用
/**
* 演示PreparedStatement
* @throws SQLException
*/
@Test
public void testPreparedStatement() throws SQLException {
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/sql_base";
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//sql语句
String sql = "select * from user where name = ? and password = ?";
//获取用户输入的账号和密码
String name = "张三";
String pas = "123";
//获取sql执行对象
PreparedStatement preparedStatement = con.prepareStatement(sql);
//?号替换
preparedStatement.setString(1,name);
preparedStatement.setString(2,pas);
//执行sql语句
ResultSet rs = preparedStatement.executeQuery();
//处理数据
if(rs.next()){
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
System.out.println(sql);
//7.释放资源 注意释放的先后顺序 先开后释放
rs.close();
preparedStatement.close();
con.close();
}
PreparedStatement原理
/**
* 演示PreparedStatement原理
* @throws SQLException
*/
@Test
public void testPreparedStatement2() throws SQLException {
//2.获取连接
String url = "jdbc:mysql:///sql_base?useServerPrepStmts=true";//开启预处理
String user = "root";
String password = "123456";
Connection con = DriverManager.getConnection(url,user,password);
//sql语句
String sql = "select * from user where name = ? and password = ?";//预处理只需要做一次 每次采用相同模板 性能更高
//获取用户输入的账号和密码
String name = "张三";
String pas = "123";
//获取sql执行对象
PreparedStatement preparedStatement = con.prepareStatement(sql);
//?号替换
preparedStatement.setString(1,name);
preparedStatement.setString(2,pas);
//执行sql语句
ResultSet rs = preparedStatement.executeQuery();
//处理数据
if(rs.next()){
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
System.out.println(sql);
//7.释放资源 注意释放的先后顺序 先开后释放
rs.close();
preparedStatement.close();
con.close();
}
日志文件的配置
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2
四.数据库连接池
简介
-
数据库连接池是个容器,负责分配,管理数据库连接
-
它允许应用程序重复使用一个现有的数据库连接,而不是重新建立
-
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库来连接而引起的数据库连接遗漏
-
好处:
资源重复利用
提升系统相应速度
避免数据库连接遗漏
数据库实现
标准接口:DataSource
常见的数据库连接池:DBCP C3P0 Druid
package druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
public class DruidDemo1 {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定于配置文件
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-dome/src/druid.properties"));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接 Connection
Connection con = dataSource.getConnection();
System.out.println(con);
System.out.println(System.getProperty("user.dir"));
}
}