JDBC引入
JDBC概念:
JDBC是使用Java语言操作关系型数据库的一套API。全称:(Java DataBase Connectivity)Java数据库连接
JDBC的本质:
官方定义的一套操作所有关系型数据库的规则,即接口。
各个数据库厂商去实现这套接口,即提供实现类,这些实现类也叫做驱动, 厂商提供的是相应的数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的是驱动jar包中的实现类。
JDBC的好处:
各数据库厂商使用相同的接口,Java代码不需要针对不同的数据库分别开发。可随时替换底层数据库,访问数据库的Java代码基本不变。
JDBC的使用步骤
有七步,如代码所示:
package JDBC学习;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class test1 {
public static void main(String[] args) {
Connection conn = null;
Statement sta = null;
try {
//1 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2 获取连接
String url = "jdbc:mysql://127.0.0.1:3306/limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url, username, password);
//3 定义SQL
String sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";
//4 获取执行sql的对象Statement
sta = conn.createStatement();
//5 执行sql
int i = sta.executeUpdate(sql_1);//i为受影响的行数
//6 处理结果
System.out.println(i);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//7 释放资源
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注:mysql5.0之后可以省略注册驱动一步。
JDBC API详解
DiverManager
DiverManager(驱动管理类)作用:
- 注册驱动
- 获取数据库连接
关于DiverManager中的静态方法static Connection getConnection(String url,String user,String password)
参数:
- url:连接路径
- user:用户名
- password:密码
Connection
Connection(数据库连接对象)作用:
- 获取执行SQL的对象
- 管理事务
获取执行SQL的对象
- 普通执行SQL对象
Statement createStatement()
- 预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement preparedStatement(sql)
- 执行存储变量的对象
CallableStatement prepareCall(sql)
事务管理
可以利用JDBC的三个方法来管理事务:
package JDBC学习;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class test2 {
public static void main(String[] args) {
Connection conn = null;
Statement sta = null;
try {
//1 注册驱动
//Class.forName("com.mysql.cj.jdbc.Driver");
//2 获取连接
String url = "jdbc:mysql://127.0.0.1:3306/limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url, username, password);
//3 定义SQL
String sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";
String sql_2 = "UPDATE emp1 SET salary = 20000 WHERE `name` = '丘丘人'";
//4 获取执行sql的对象Statement
sta = conn.createStatement();
//开启事务
conn.setAutoCommit(false);
//5 执行sql
int i = sta.executeUpdate(sql_1);//i为受影响的行数
int j = sta.executeUpdate(sql_2);//i为受影响的行数
//6 处理结果
System.out.println(i);
System.out.println(j);
//提交事务
conn.commit();
} /*catch (ClassNotFoundException e) {
e.printStackTrace();
} */catch (SQLException e) {
//回滚事务
try {
conn.rollback();
} catch (SQLException ex) {
e.printStackTrace();
}
e.printStackTrace();
} finally {
//7 释放资源
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
先设置MySQL不自动提交事务,在try中末尾处加上提交事务的操作。如果出现异常,说明此异常操作的事务不应该提交,要回滚事务。将回滚事务的操作放在catch中,随着和对异常的处理操作一起进行回滚操作。
Statement
Statement作用:
执行SQL语句。
执行SQL语句
int executeUpdate(sql):执行DML、DDL语句
返回值:①DML语句影响的行数 ②DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql):执行DQL语句
返回值:ResultSet结果集对象
ResultSet
Result(结果集对象)作用:
封装了DQL查询语句的结果
ResultSet executeQuery(sql):执行DQL语句
返回值:ResultSet结果集对象
获取查询结果
boolean next():①将指针从当前位置移动到下一行 ②判断当前行是否为有效行
返回值:true,有效行,当前行有数据;false,无效行,当前行没有数据。
xxx getXxx(参数):获取数据
xxx:数据类型。如int getInt()、String getString(参数)
参数:int,列的编号,从1开始。String:列的名称。
使用
使用时通常会用上while循环
while(…….next()){
……
…….getXxx(参数);
}
例:查询员工表emp1中的数据并打印。
@Test
void test3() {
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
//获取连接(注册驱动已省略)
String url = "jdbc:mysql:///limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url,username,password);
//定义SQL语句
String sql_1 = "select * from emp1";
//获取statement对象
sta = conn.createStatement();
//执行sql
rs = sta.executeQuery(sql_1);
//处理结果,遍历查询的所有结果
while(rs.next())
{
int id = rs.getInt("id");
String name = rs.getString(2);
Date date = rs.getDate(3);
double salary = rs.getDouble("salary");
System.out.print(id + "\t");
System.out.print(name + "\t");
System.out.print(date + "\t");
System.out.print(salary + "\t");
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//释放资源
try {
rs.close();
sta.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
还可以使用其查询数据做Java代码的处理,例:将员工的sal添加到一个Arraylist中。
@Test
void test4() {
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
//获取连接(注册驱动已省略)
String url = "jdbc:mysql:///limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url,username,password);
//定义SQL语句
String sql_1 = "select salary from emp1";
//获取statement对象
sta = conn.createStatement();
//执行sql
rs = sta.executeQuery(sql_1);
//处理结果,遍历查询的所有结果
ArrayList<Double> sal = new ArrayList<>();
while(rs.next())
{
double salary = rs.getDouble("salary");
sal.add(salary);
}
Iterator ii = sal.iterator();
while (ii.hasNext())
{
System.out.println(ii.next());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//释放资源
try {
rs.close();
sta.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
例:将员工的信息添加到一个Arraylist中。
@Test
void test5() {
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
//获取连接(注册驱动已省略)
String url = "jdbc:mysql:///limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url,username,password);
//定义SQL语句
String sql_1 = "select * from emp1";
//获取statement对象
sta = conn.createStatement();
//执行sql
rs = sta.executeQuery(sql_1);
//处理结果,遍历查询的所有结果
ArrayList<Employee> employees = new ArrayList<>();
while(rs.next())
{
int id = rs.getInt(1);
String name = rs.getString("name");
Date date = rs.getDate(3);
double salary = rs.getDouble("salary");
employees.add(new Employee(id,name,date,salary));
}
Iterator ii = employees.iterator();
while (ii.hasNext())
{
System.out.println(ii.next());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//释放资源
try {
rs.close();
sta.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
PreparedStatement
PreparedStatement作用:
预编译SQL语句并执行:预防SQL注入问题
SQL注入
即利用SQL语句的语法,在填入时,强制查询结果为true。
操作
①获取PrepareStatement对象
//SQL语句中的参数值,使用?占位符替代
String sql = "SELECCT * FROM user WHERE username = ? AND password = ?";
//通过Connection对象获取,并传入相应的SQL语句。
PreparedStatement psta = conn.prepareStatement(sql);
②设置参数值
PreparedStatement对象:setXxx(参数1,参数2):给?赋值
Xxx指的是数据类型,参数1是?的顺序编号,从一开始。参数2是?的具体的值。
③执行SQL
使用:executeUpdate()/executeQuery():不需要再传入SQL语句。
例:
@Test
void test7()
{
Connection conn = null;
PreparedStatement psta = null;
ResultSet rs = null;
try {
//获取连接
String url = "jdbc:mysql:///limingmao";
String username = "liergou";
String password = "liergou070509";
conn = DriverManager.getConnection(url,username,password);
//接收用户输入的用户名和密码
String uname = "张三";
String pwd = "1234";
//定义SQL
String sql = "SELECT * FROM tb_user WHERE username = ? AND password = ?";
//获取psta对象
psta = conn.prepareStatement(sql);
//设置?的值
psta.setString(1,uname);
psta.setString(2,pwd);
//执行SQL语句
rs = psta.executeQuery();
//判断是否成功
if(rs.next()) {
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//释放资源
rs.close();
psta.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
PreparedStatement原理
- 在获取PreparedStatement对象时,将SQL语句发送给MySQL服务器进行检查、编译
- 执行时就不用再进行这些步骤了,速度更快
- 如果SQL模板一样,则只需要进行一次检查、编译
PreparedStatement好处:
- 预编译SQL,性能更高
- 防止SQL注入:将敏感字符进行转义
开启预编译功能:
userServerPrepStmts=true:将此参数键值对放到url的参数键值对处。
数据库连接池
简介
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
好处:
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
数据库连接池实现
标准接口:DataSource
官方提供的数据库连接池标准接口,由第三方组织实现此接口。
功能:获取连接
Connection getConnection()
常见的数据库连接池:
- DBCP
- C3P0
- Druid
Druid(德鲁伊)
Druid连接池是阿里巴巴开源的数据库连接池项目
功能强大,性能优秀,是Java语言最好的数据库连接池之一
使用步骤以及代码实现如下:
public class test_druid {
public static void main(String[] args){
try {
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("D:\\李明茂\\Java学习\\JDBC\\src\\druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
System.out.println(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDBC练习:实现品牌列表的增删查改
要求:使用数据库连接池(德鲁伊),使用预编译防SQL注入的PreparedStatement
题目准备:
数据库准备:
CREATE TABLE tb_brand(
id INT PRIMARY KEY AUTO_INCREMENT,
brand_name VARCHAR(20),-- 品牌名称
company_name VARCHAR(20),-- 企业名称
ordered INT,-- 排序字段
description VARCHAR(100),-- 描述信息
`status` INT-- 状态 0表示禁用,1表示启用
);
INSERT INTO tb_brand(brand_name,company_name,ordered,description,`status`)
VALUES('金坷拉','金坷垃股份有限公司',5,'要种庄稼,必须要有金坷垃',0),
('米哈游','米哈游技术有限公司',100,'技术宅拯救世界',1),
('腾讯','腾讯技术有限公司',50,'下元梦之心',1);
SELECT * FROM tb_brand;
DESC tb_brand;
Java中Brand类的准备:
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;
public Brand() {
}
public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
this.id = id;
this.brandName = brandName;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
开始练习:
查所有数据:(单元测试方法中实现,下同)
/**
* 查询所有
* SQL语句:SELECT * FROM tb_brand;
* 参数:不需要
* 结果:List<Brand>
*/
@Test
public void testSelectAll(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("D:\\李明茂\\Java学习\\JDBC\\src\\druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
conn = dataSource.getConnection();
//定义SQL语句
String sql = "SELECT * FROM tb_brand";
//获取PreparedStatement对象
pstmt = conn.prepareStatement(sql);
//执行SQL语句
rs = pstmt.executeQuery();
//处理结果
List<Brand> brands = new ArrayList<>();
while(rs.next())
{
brands.add(
new Brand(
rs.getInt("id"),
rs.getString(2),
rs.getString(3),
rs.getInt(4),
rs.getString("description"),
rs.getInt(6)
)
);
}
Iterator ii = brands.iterator();
while (ii.hasNext())
{
System.out.println(ii.next());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
增:
/**
* 添加
* SQL语句:
* INSERT INTO tb_brand(brand_name,company_name,ordered,description,`status`) VALUES(?,?,?,?,?);
* 参数:需要,除了id之外的所有参数,共五个。
*/
@Test
public void testAdd()
{
Connection conn = null;
PreparedStatement pstmt = null;
//假设接受到的添加的信息如下:
String brandName = "网易";
String companyName = "网易技术有限公司";
Integer ordered = 1;
String description = "下蛋仔派对";
Integer status = 1;
try {
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("D:\\李明茂\\Java学习\\JDBC\\src\\druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
conn = dataSource.getConnection();
//定义SQL语句
String sql = "INSERT INTO tb_brand(brand_name,company_name,ordered,description,`status`) VALUES(?,?,?,?,?);";
//获取PreparedStatement对象
pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
//执行SQL语句
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
改:
/**
* 修改
* SQL语句:UPDATE tb_brand SET brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ? WHERE id = ?;
*/
@Test
public void testUpdate()
{
Connection conn = null;
PreparedStatement pstmt = null;
//假设接受到的添加的信息如下:
String brandName = "网易";
String companyName = "网易技术有限公司";
Integer ordered = 1;
String description = "66666";
Integer status = 1;
Integer id = 4;
try {
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("D:\\李明茂\\Java学习\\JDBC\\src\\druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
conn = dataSource.getConnection();
//定义SQL语句
String sql = "UPDATE tb_brand SET brand_name = ?,company_name = ?,ordered = ?,description = ?,status = ? WHERE id = ?;";
//获取PreparedStatement对象
pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id);
//执行SQL语句
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
删:
/**
* 删除
* SQL语句:DELETE FROM tb_brand WHERE id = ?;
*/
@Test
public void testDelete()
{
Connection conn = null;
PreparedStatement pstmt = null;
//假设接受到的添加的信息如下:
Integer id = 4;
try {
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("D:\\李明茂\\Java学习\\JDBC\\src\\druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
conn = dataSource.getConnection();
//定义SQL语句
String sql = "DELETE FROM tb_brand WHERE id = ?;";
//获取PreparedStatement对象
pstmt = conn.prepareStatement(sql);
//设置参数
pstmt.setInt(1,id);
//执行SQL语句
int count = pstmt.executeUpdate();
//处理结果
System.out.println(count > 0);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}