1. JDBC简介
JDBC全称:java数据库连接(java database connectivity),它定义了一套标准接口用于操作各种关系型数据库
2. JDBC快速入门
步骤:
0、创建工程,导入对应关系型数据库jar包
首先将要到如的包放置在模块新建的文件夹中,然后add as library将包导入
1、注册驱动
Class.forName(“com.mysql.jdbc.Driver”);
2、获取连接
Connection conn = DriverManager.getConnection(url,usename,password);
3、定义sql语句
String sql = “update …”;
4、获取执行sql对象
Statement stmt = conn.createStatement();
5、执行sql
stmt.executeUpdate(sql);
6、处理返回结果
7、释放资源
代码案例:
package com.lyy.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
/*
* JDBC快速入门
* */
public class JDBCdemo {
public static void main(String[] args) throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//定义sql
String sql = "update account set money = 2000 where id =1";
//获取执行sql的对象 Statement
Statement statement = conn.createStatement();
//执行sql
int count = statement.executeUpdate(sql);//受影响的行数
//处理结果
System.out.println(count);
//释放资源
statement.close();
conn.close();
}
}
代码执行前后account表数据的变化:
3.JDBC API详解
- DriverManager 获取Connection连接对象
- Connection
- Statement
- ResultSet 对查询结果进行封装
- PreparedStatement Statement的加强版
3.1 DriverManager
DriverManager (驱动管理类)作用:
1、注册驱动
2、获取数据库连接
1、注册驱动:
Class.forName("com.mysql.cj.jdbc.Driver");
- static void registerDriver(Driver driver):使用DriverManager 注册给定的驱动程序 。
查看Driver类码源,底层是用DriverManager类中的registerDriver()方法进行实现的
MySQL5之后的驱动包,可省略注册驱动的步骤,原因是自动加载了jar包中的META-INF/services/java.sql.Driver文件中的驱动类
2、获取连接
- static Connection getConnection(String url, Properties info) :尝试建立与给定数据库URL的连接。
Connection conn = DriverManager.getConnection(url, username, password);
参数:
- URL 连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
localhost或127.0.0.1为本机地址,3306为MySQL默认的端口号
示例:jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8 - user:用户名
- password:密码
3.2 Connection 接口
Connection(数据库连接对象)作用:
1、获取执行SQL的对象
2、管理事务
1、获取执行SQL的对象
- 普通执行SQL对象
Statement createStatement():创建一个 Statement对象,用于将SQL语句发送到数据库。 - 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(String sql) :创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。 - 执行存储过程的对象
CallableStatement prepareCall(String sql) :执行存储过程的对象(不常用)
2、事务管理
- MySQL事务管理
开启事务:begin/start transaction
提交事务:commit
回滚事务:rollback
MySQL默认自动提交事务 - JDBC管理事务:Connection接口中定义了3个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务
提交事务:commit()
回滚事务:rollback()
JDBC事务管理操作示例,使用try…catch方法,当抛出异常时在catch里面进行回滚事务。
package com.lyy.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*
* JDBC快速入门
* */
public class JDBCdemo_Connection {
public static void main(String[] args) throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//定义sql
String sql1 = "update account set money = 3000 where id =1";
String sql2 = "update account set money = 3000 where id =2";
//获取执行sql的对象 Statement
Statement statement = conn.createStatement();
//用事务对sql语句进行管理
//开启事务
conn.setAutoCommit(false);
try {
//执行sql1
int count1 = statement.executeUpdate(sql1);//受影响的行数
//处理结果
System.out.println(count1);
//执行sql2
int count2 = statement.executeUpdate(sql2);//受影响的行数
//处理结果
System.out.println(count2);
//提交事务
conn.commit();
} catch (Exception throwablse) {
//回滚事务
conn.rollback();
throwablse.printStackTrace();
}
//释放资源
statement.close();
conn.close();
}
}
3.3 Statement 接口
Statement 的作用:
1、执行SQL语句
执行SQL语句:
- int executeUpdate(String sql) :执行给定DML、DDL的SQL语句
返回值:(1)DML语句影响的行数(2)DDL语句执行后,执行成功也可能返回0 - ResultSet executeQuery(String sql) :执行DQL语句
返回值:ResultSet 结果集合对象
DDL 数据定义语言,用来定义数据库对象;数据库,表,列等
DML 数据操作语言,用来对数据库中表的数据进行增删改
DQL 数据查询语言,用来查询数据库表的记录(数据)
package com.lyy.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCdemo_Statement {
/*
* 执行DML语句
* */
@Test
public void testDML() throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//定义sql
String sql = "update account set money = 2000 where id =1";//执行完DML语句,受影响的行数
//获取执行sql的对象 Statement
Statement statement = conn.createStatement();
//执行sql
int count = statement.executeUpdate(sql);//受影响的行数
//处理结果
// System.out.println(count);
if (count >0){
System.out.println("修改成功");
}else {
System.out.println("修改失败");
}
//释放资源
statement.close();
conn.close();
}
/*
* 执行DDL语句
* */
@Test
public void testDDL() throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//定义sql
//执行DDL语句范围值可能是0,不能根据返回值判定是否执行成功
// String sql = "create database if not exists db2";//创建新的数据库db2
String sql = "drop database if exists db2";//删除数据库db2,
//获取执行sql的对象 Statement
Statement statement = conn.createStatement();
//执行sql
int count = statement.executeUpdate(sql);//受影响的行数
//处理结果
// System.out.println(count);
/* if (count >0){
System.out.println("修改成功");
}else {
System.out.println("修改失败");
}*/
//释放资源
statement.close();
conn.close();
}
}
3.4 ResultSet 接口
ResultSet (结果集对象)作用:
1、封装了DQL查询语句的结果
ResultSet statement.executeQuery(sql) :执行DQL语句,返回ResultSet对象
获取查询结果:
- boolean next() :(1)将光标从当前位置向前移动一行 (2)判断当前行是否为有效行
返回值:(1)true:有效行,当前行有数据(2)false:无效行当前行没有数据 - xxx getXxx(参数) :获取数据
xxx:数据类型;如:int getInt(参数);String getString(参数)
参数:int:列的编号,从1开始;String:列的名称
使用步骤:
1、游标向下移动一行,判断改行是否有数据:next()
2、获取数据:getXxx(参数)
代码:
while(rs.next()){
rs.getXxx(参数);
}
package com.lyy.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBCdemo_ResultSet {
/*
* 执行DQL语句
* */
@Test
public void testResult() throws Exception {
//1、注册驱动
// MySQL第五个版本及以上该语句就不用写了
// Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
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中的所有数据
//光标向下移动一行,并且判断当前行是否有数据
// while (rs.next()){
// //获取数据
// int id = rs.getInt(1);
// String name = rs.getString(2);
// double money = rs.getDouble(3);
//
// System.out.print(id+" ");
// System.out.print(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.print(id+" ");
System.out.print(name+" ");
System.out.println(money);
System.out.println("---------------------");
}
//7、释放资源
rs.close();
stmt.close();
conn.close();
}
}
案例:从MySQL表中读取数据并存入集合
创建Account类
package com.lyy.jdbc;
public class Account {
private int id;
private String name;
private String money;
//无参构造
public Account(){
}
//有参构造
public Account(int id,String name,String money){
this.id = id;
this.name = name;
this.money = money;
}
//get和set方法
public void setId(int id) {
this.id = id;
}
public void setName(String name){
this.name = name;
}
public void setMoney(String money){
this.money = money;
}
public int getId() {
return id;
}
public String getName(){
return name;
}
public String getMoney(){
return money;
}
}
利用JDBC读取数据,将数据赋值给Account对象,将account对象存储到集合中
package com.lyy.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
public class JDBC_Arraylist {
public static void main(String[] args) throws Exception {
//创建集合对象用于存储表中数据
ArrayList<Account> array = new ArrayList<Account>();
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";
String user = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, user, password);
//定义sql语句
String sql = "select * from account";
//获取Statement对象
Statement stmt = conn.createStatement();
//执行sql语句
ResultSet rs = stmt.executeQuery(sql);//executeQuery执行DQL查询语句
//遍历rs中的所有数据
//光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
//获取数据
int id = rs.getInt("id");
String name = rs.getString("name");
String money = rs.getString("money");
//创建Account 对象
Account a = new Account(id,name,money);
//将Account 对象加入集合
array.add(a);
}
//释放资源
rs.close();
stmt.close();
conn.close();
//遍历array 输出集合中的元素
// for (Account arr:array){
// System.out.println(arr.getId()+","+arr.getName()+","+arr.getMoney());
// }
//迭代器方法
Iterator<Account> it = array.iterator();
while (it.hasNext()){
Account arr = it.next();
System.out.println(arr.getId()+","+arr.getName()+","+arr.getMoney());
}
}
}
3.5 PrepareStatement 接口
PrepareStatement 作用:
1、预编译SQL语句并执行,预防SQL注入问题
(SQL注入的其中一种是由字符串拼接导致的)
SQL注入:SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
sql注入演示案例:
package com.lyy.jdbc;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCdemo_UserLogin {
@Test
public void testLogin() throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//接收用户名和密码
String name = "zhangsan";
String pwd = "123";
// String sql1 = "create table if not exists tb_user(id int,username varchar(20),password varchar(32))";
// String sql2 = "insert into tb_user values(1,'zhangsan','123'),(2,'lisi','234')";
String sql = "select * from tb_user where username='"+name+"' and password='"+pwd+"'";
//获取stmt 对象
Statement stmt = conn.createStatement();
//执行sql executeUpdate用于增删改 executeQuery用于查询
// int count1 = stmt.executeUpdate(sql1);
// int count2 = stmt.executeUpdate(sql2);
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//7、释放资源
rs.close();
stmt.close();
conn.close();
}
//演示sql注入
@Test
public void testLogin_Inject() throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//接收用户名和密码
String name = "dajhidiah";
String pwd = "'or '1'='1";
// String sql1 = "create table if not exists tb_user(id int,username varchar(20),password varchar(32))";
// String sql2 = "insert into tb_user values(1,'zhangsan','123'),(2,'lisi','234')";
String sql = "select * from tb_user where username='"+name+"' and password='"+pwd+"'";
System.out.println(sql);
//select * from tb_user where username='dajhidiah' and password=''or '1'='1'
//该sql语句username输出false password输出false 语句就变成 (where false and false or true = where true)
//即select * from tb_user where true, 输出了所有的账户密码信息
//获取stmt 对象
Statement stmt = conn.createStatement();
//执行sql executeUpdate用于增删改 executeQuery用于查询
// int count1 = stmt.executeUpdate(sql1);
// int count2 = stmt.executeUpdate(sql2);
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//7、释放资源
rs.close();
stmt.close();
conn.close();
}
}
PrepareStatement 的使用:
1、获取PrepareStatement 对象
//SQL语句中的参数使用?占位符代替
String sql ="select * from tb_user where username=? and password=?";
PrepareStatement pstmt = conn.prepareStatement(sql);
2、设置参数值
PrepareStatement 对象:setXxx(参数1,参数2):给?赋值
Xxx:数据类型;
参数:
参数1:?的位置编号,从1开始
参数2:?的值
3、执行sql
executeUpdate();/executeQuery(); 不需要再传递sql
代码案例:
public class JDBCdemo_PrepareStatement {
@Test
public void testPrepareStatement() throws Exception {
//获取连接
String url ="jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8";//localhost为本机地址,3306端口号
String username = "root";
String password = "lyy751227";
Connection conn = DriverManager.getConnection(url, username, password);
//接收用户名和密码
String name = "zhangsan";
String pwd = "1234";
//定义sql
String sql = "select * from tb_user where username=? and password=?";
//获取PrepareStatement 对象
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();
}
}
3.5 PrepareStatement 原理
PrepareStatement 好处:
- 预编译SQL,性能更高
- 防止SQL注入,将敏感字符进行转义
PrepareStatement 预编译功能开启:useServerPrepStmts=true(在获取连接时的URL后面添加该语句)
PrepareStatement 原理:
- 在获取PrepareStatement 对象时,将sql语句发送给MySQL服务器进行检查,编译
- 执行时就不用再进行这些步骤了,速度更快
- 如果sql模板一样只需呀进行一次检查编译
3.6 数据库连接池
- 数据库连接池是个容器,负责分配、管理数据库连接
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
- 好处:资源重用;提升系统响应速度;避免数据库连接遗漏
数据库连接池实现
标准接口:DataSource
- 官方提供的数据库连接池标准接口,由第三方组织实现此接口。
- 功能:获取连接
常见的数据库连接池:
- DBCP
- C3P0
- Druid
Druid(德鲁伊)
- Druid连接池是阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,是java语言最好的数据库连接池之一。
Druid使用步骤
1、导入jar包
把jar包添加到library
2、定义配置文件
新建一个druid.properties配置文件,写入一下内容
driverClassName=com.mysql.cj.jdbc.Driver
#URL连接数据库的URL,其中db1(以下面例子来说)为连接的数据库,后面的参数可不改但不删
url=jdbc:mysql://localhost:3306/db1?serverTimezone=GMT%2B8 & useSSL=false & useServerPrepStmts=true
#安装mysql时候设置的用户与密码
username=root
password=lyy751227
#初始化物理连接的个数
initialSize=5
#最大连接池数量
maxActive=10
#获取连接时最大等待时间
maxWait=3000
3、加载配置文件
4、获取数据库连接池对象
5、获取连接
package com.lyy.druid;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
/*
* Druid 数据库连接操作
* */
public class Druid {
public static void main(String[] args) throws Exception {
//导入jar包
//定义配置文件
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
// System.out.println(System.getProperty("user.dir"));
}
}