文章目录
一.JDBC初始
1.1 概述
JDBC 就是使用Java语言操作关系型数据库的一套API
全称:( Java DataBase Connectivity ) Java 数据库连接
1.2 JDBC本质
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
1.3 使用JDBC步骤
-
创建工程,导入驱动jar包
在lib文件夹下导入包
如何获取jar包:【点击这里】
-
注册驱动
Class.forName("com.mysql.jdbc.Driver"); 或者 Class.forName("com.mysql.cj.jdbc.Driver"); com.mysql.jdbc.Driver是mysql-connector-java 5中的 com.mysql.cj.jdbc.Driver是mysql-connector-java 6以及以上中的
-
获取连接
Connection conn = DriverManager.getConnection(url, username, password);
Java代码需要发送SQL给MySQL服务端,就需要先建立连接
-
PreparedStatement
String sql = “update…” ;
-
获取执行SQL对象
执行SQL语句需要SQL执行对象,而这个执行对象就是Statement对象
Statement stmt = conn.createStatement();
-
执行SQL
stmt.executeUpdate(sql);
-
处理返回结果
-
释放资源
示例代码:
public class JdbcDemo {
public static void main(String[] args) throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
//jdbc:mysql://localhost:3306/数据库名
String url = "jdbc:mysql://localhost:3306/stu";
//数据库用户名
String username = "root";
//数据库用户名的密码
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql="update score set math = 88 where id = 1";
//4. 获取执行sql的对象
Statement statement = connection.createStatement();
// 5.执行sql
int count = statement.executeUpdate(sql);//受影响行数
System.out.println(count);
// 6.释放资源
statement.close();
connection.close();
}
}
二.JDBC API详解
2.1 DriverManager
DriverManager(驱动管理类)作用:
作用一:注册驱动
registerDriver方法是用于注册驱动的,但是我们之前做的入门案例并不是这样写的。而是如下实现
Class.forName("com.mysql.jdbc.Driver");
查询MySQL提供的Driver类,看它是如何实现的,源码如下:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
在该类中的静态代码块中已经执行了 DriverManager
对象的 registerDriver()
方法进行驱动的注册了,那么我们只需要加载 Driver
类,该静态代码块就会执行。而 Class.forName("com.mysql.jdbc.Driver");
就可以加载 Driver
类。
作用二:获取数据库连接
参数说明:
-
url : 连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
示例:jdbc:mysql://127.0.0.1:3306/db1
细节:
-
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
-
配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
-
-
user :用户名
-
poassword :密码
2.2 Connection
Connection(数据库连接对象)作用:
- 获取执行 SQL 的对象
- 管理事务
2.2.1 获取执行对象
-
普通执行SQL对象
Statement createStatement()
入门案例中就是通过该方法获取的执行对象。
-
预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
通过这种方式获取的
PreparedStatement
SQL语句执行对象是重点,它可以防止SQL注入。 -
执行存储过程的对象
CallableStatement prepareCall(sql)
通过这种方式获取的
CallableStatement
执行对象是用来执行存储过程的,而存储过程在MySQL中不常用
2.2.2 事务管理
MySQL事务管理的操作:
- 开启事务 : BEGIN; 或者 START TRANSACTION;
- 提交事务 : COMMIT;
- 回滚事务 : ROLLBACK;
MySQL默认是自动提交事务
Connection接口中定义了3个对应的方法:
-
开启事务
connection.setAutoCommit(boolean autoCommit); true:自动提交事务 false:手动提交事务,即为开启事务
-
提交事务
commit()
-
回滚事务
rollback()
示例代码:
public class JdbcDemo03 {
public static void main(String[] args) throws Exception {
// 详解Connection
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/stu";
String username = "root";
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql1 ="update score set math = 99 where id = 1";
String sql2 ="update score set chinese = 99 where id = 1";
//4. 获取执行sql的对象
Statement statement = connection.createStatement();
try {
// 开始事务(手动提交事务)
connection.setAutoCommit(false);
// 5.执行sql
//受影响行数
int count1 = statement.executeUpdate(sql1);
// 处理结果
System.out.println(count1);
// 制造异常
int a = 3/0;
//受影响行数
int count2 = statement.executeUpdate(sql2);
System.out.println(count2);
// 提交事务
connection.commit();
} catch (Exception e) {
// 回滚事务
connection.rollback();
e.printStackTrace();
}
// 6.释放资源
statement.close();
connection.close();
}
}
2.3 Statement
作用就是用来执行SQL语句
- 执行DDL、DML语句
- 执行DQL语句
public class JdbcDemo04 {
// 执行DML语句
@Test
public void testDML() throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/stu";
String username = "root";
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "update score set math = 88 where id = 1";
//4. 获取执行sql的对象
Statement statement = connection.createStatement();
// 5.执行sql
int count = statement.executeUpdate(sql);//受影响行数
// 6.处理结果
// System.out.println(count);
if(count > 0){
System.out.println("修改成功~");
}else{
System.out.println("修改失败~");
}
// 6.释放资源
statement.close();
connection.close();
}
@Test
public void testDDL() throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/stu";
String username = "root";
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "drop database db2";
//4. 获取执行sql的对象
Statement statement = connection.createStatement();
// 5.执行sql
int count = statement.executeUpdate(sql);//受影响行数
// 6.处理结果
System.out.println(count);
// 6.释放资源
statement.close();
connection.close();
}
}
2.4 ResultSet
ResultSet使用
ResultSet(结果集对象)作用:
- 封装了SQL查询语句的结果。
而执行了DQL语句后就会返回该对象,对应执行DQL语句的方法如下:
ResultSet executeQuery(sql):执行DQL 语句,返回 ResultSet 对象
那么我们就需要从 ResultSet
对象中获取我们想要的数据。ResultSet
对象提供了操作查询结果数据的方法,如下:
boolean next()
- 将光标从当前位置向前移动一行
- 判断当前行是否为有效行
方法返回值说明:
- true : 有效航,当前行有数据
- false : 无效行,当前行没有数据
xxx getXxx(参数):获取数据
- xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
- 参数
- int类型的参数:列的编号,从1开始
- String类型的参数: 列的名称
示例代码:
public class JdbcDemo05 {
// 详解Result
// 执行DQL语句
@Test
public void testResult() throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/stu";
String username = "root";
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "select * from score";
// 4.获取statement对象,用来执行sql语句
Statement statement = connection.createStatement();
// 5.执行sql
ResultSet res = statement.executeQuery(sql);
// 6.遍历res中所有数据
while (res.next()) {
// int id = res.getInt(1);
// String name = res.getString(2);
// int score = res.getInt(3);
int id = res.getInt("id");
String name = res.getString("name");
int score = res.getInt("math");
System.out.println(id);
System.out.println(name);
System.out.println(score);
System.out.println("-----------");
}
// 6.释放资源
res.close();
statement.close();
connection.close();
}
}
练习
需求:已知stu数据库中有张表student,将表中数据封装到实体类User中,并添加到集合中再打印集合。
创建实体类:
package com.itzh.pojo;
public class User {
//根据数据库student表中字段创建成员变量
private Integer id;
private String name;
private String no;
public User() {}
public User(Integer id, String name, String no) {
this.id = id;
this.name = name;
this.no = no;
}
//省略get、set、toString方法
}
@Test
public void testResult02() throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/stu";
String username = "root";
String password = "xxxxx";
Connection connection = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "select * from student";
// 4.获取statement对象,用来执行sql语句
Statement statement = connection.createStatement();
// 5.执行sql
ResultSet res = statement.executeQuery(sql);
// 创建集合用来封装实体类对象
List<User> userList = new ArrayList<>();
// 6.遍历res中所有数据
while (res.next()) {
// int id = res.getInt(1);
// String name = res.getString(2);
// String no = res.getString(3);
int id = res.getInt("id");
String name = res.getString("name");
String no = res.getString("no");
// 创建用户对象,并将遍历的数据封装到对象中
User user = new User(id,name,no);
// 将对象添加到集合中
userList.add(user);
}
// 打印集合中对象
System.out.println(userList);
// 6.释放资源
res.close();
statement.close();
connection.close();
}
2.5 PreparedStatement
2.5.1 PreparedStatement用处
PreparedStatement又是如何解决SQL注入漏洞问题的呢?它是将特殊字符进行了转义.
示例代码:解决SQL注入问题
@Test
public void testPreparedStatement() throws Exception {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///stu?useSSL=false";
String username = "root";
String password = "xxxxx";
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);
// 设置?的值
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();
}
2.5.2 PreparedStatement原理
三.数据库连接池
3.1 概述
-
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
-
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
-
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
-
好处
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
3.2 数据库连接池实现
-
标准接口:DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
Connection getConnection()
那么以后就不需要通过
DriverManager
对象获取Connection
对象,而是通过连接池(DataSource)获取Connection
对象。 -
常见的数据库连接池
- DBCP
- C3P0
- Druid
我们现在使用更多的是Druid,它的性能比其他两个会好一些。
-
Druid(德鲁伊)
-
Druid连接池是阿里巴巴开源的数据库连接池项目
-
功能强大,性能优秀,是Java语言最好的数据库连接池之一
-
Driud使用
- 导入jar包 druid-1.1.12.jar
- 定义配置文件
- 加载配置文件
- 获取数据库连接池对象
- 获取连接
首先需要先将druid的jar包放到项目下的lib下并添加为库文件
编写配置文件如下:
driverClassName=com.mysql.cj.jdbc.Driver
# stu是自己的数据库
url=jdbc:mysql:///stu?useSSL=false&useServerPrepStmts=true
username=root
password=sa123456
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
示例代码:
public class DruidDemo {
public static void main(String[] args) throws Exception {
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop = new Properties();
prop.load(
new FileInputStream("jdbc/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"));
}
}
3.3 练习
(用数据库连接池)
完成商品品牌数据的增删改查操作
- 查询:查询所有数据
- 添加:添加品牌
- 修改:根据id修改
- 删除:根据id删除
数据准备:
-
数据库表
tb_brand
在stu数据库中创建tb_brand表,因为在配置文件中连接的是stu数据库
-- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand ( -- id 主键 id int primary key auto_increment, -- 品牌名称 brand_name varchar(20), -- 企业名称 company_name varchar(20), -- 排序字段 ordered int, -- 描述信息 description varchar(100), -- 状态:0:禁用 1:启用 status int ); -- 添加数据 insert into tb_brand (brand_name, company_name, ordered, description, status) values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0), ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1), ('小米', '小米科技有限公司', 50, 'are you ok', 1);
实体类:在pojo包下实体类 Brand
package com.itzh.pojo;
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;
// 省略无参构造、带参构造、get/set方法、toString方法
}
3.3.1 查询所有数据
@Test
public void selectTest() throws Exception {
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("E:\\software\\ideak\\ideapro\\kwhcode\\jdbc\\src\\druid.properties"));
// 4.获取连接对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 connection
Connection conn = dataSource.getConnection();
// 2.定义sql语句
String sql = "select * from tb_brand";
// 3.获取PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 4.设置参数
// 5.执行sql,
ResultSet res = pstmt.executeQuery();
// 创建集合用于封装实体类对象
List<Brand> brandList = new ArrayList<>();
Brand brand = null;
while (res.next()){
//获取数据
int id = res.getInt("id");
String brandName = res.getString("brand_name");
String companyName = res.getString("company_name");
int ordered = res.getInt("ordered");
String description = res.getString("description");
int status = res.getInt("status");
//封装Brand对象
brand = new Brand(id,brandName,companyName,ordered,description,status);
//装载集合
brandList.add(brand);
}
System.out.println(brandList);
//7. 释放资源
res.close();
pstmt.close();
conn.close();
}
3.3.2 添加品牌
// 新增数据
//有参数
//添加是否成功 返回布尔
@Test
public void insertTest() throws Exception {
// 模拟接收页面数据
String brandName="篮球";
String companyName="李宁";
int ordered = 1;
String description = "不一般";
int status = 1;
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("E:\\software\\ideak\\ideapro\\kwhcode\\jdbc\\src\\druid.properties"));
// 4.获取连接对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 connection
Connection conn = dataSource.getConnection();
// 2.定义sql语句
String sql = "insert into tb_brand(brand_name, company_name, ordered, description, status) " +
"values(?,?,?,?,?);";
// 3.获取PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
// 5.执行sql,
int count = pstmt.executeUpdate();
// 6.处理结果。
System.out.println(count>0);
// 释放资源
pstmt.close();
conn.close();
}
3.3.3 根据id修改
修改前:
修改后:
//根据id修改数据
//有参数
//修改是否成功返回布尔返回布尔
@Test
public void updataTest() throws Exception {
// 模拟接收页面数据
String brandName="篮球";
String companyName="李宁";
int ordered = 66;
String description = "很不一般";
int status = 1;
int id=4;
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("E:\\software\\ideak\\ideapro\\kwhcode\\jdbc\\src\\druid.properties"));
// 4.获取连接对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 connection
Connection conn = dataSource.getConnection();
// 2.定义sql语句
String sql = "update tb_brand\n" +
" set brand_name = ?,\n" +
" company_name= ?,\n" +
" ordered = ?,\n" +
" description = ?,\n" +
" status = ?\n" +
" where id = ?";
// 3.获取PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id);
// 5.执行sql,
int count = pstmt.executeUpdate();
// 6.处理结果。
System.out.println(count>0);
// 释放资源
pstmt.close();
conn.close();
}
3.3.4 根据id删除
/**
* 删除
* 1. SQL:
delete from tb_brand where id = ?
* 2. 参数:需要,id
* 3. 结果:boolean
*/
@Test
public void deleteTest() throws Exception {
// 模拟接收页面数据
int id=4;
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("E:\\software\\ideak\\ideapro\\kwhcode\\jdbc\\src\\druid.properties"));
// 4.获取连接对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 5.获取数据库连接 connection
Connection conn = dataSource.getConnection();
// 2.定义sql语句
String sql = "delete from tb_brand where id = ?";
// 3.获取PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 4.设置参数
pstmt.setInt(1,id);
// 5.执行sql,
int count = pstmt.executeUpdate();
// 6.处理结果。
System.out.println(count>0);
// 释放资源
pstmt.close();
conn.close();
}