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 定义SQLString sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";//4 获取执行sql的对象Statementsta = conn.createStatement();//5 执行sqlint 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 定义SQLString sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";String sql_2 = "UPDATE emp1 SET salary = 20000 WHERE `name` = '丘丘人'";//4 获取执行sql的对象Statementsta = conn.createStatement();//开启事务conn.setAutoCommit(false);//5 执行sqlint 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();//执行sqlrs = 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();//执行sqlrs = 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();//执行sqlrs = 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";//定义SQLString 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);//获取数据库连接ConnectionConnection 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;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';}
}
开始练习:
查所有数据:(单元测试方法中实现,下同)
/*** 查询所有* SQL语句:SELECT * FROM tb_brand;* 参数:不需要* 结果:List<Brand>*/@Testpublic 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);//获取数据库连接Connectionconn = 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之外的所有参数,共五个。*/@Testpublic 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);//获取数据库连接Connectionconn = 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 = ?;*/@Testpublic 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);//获取数据库连接Connectionconn = 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 = ?;*/@Testpublic 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);//获取数据库连接Connectionconn = 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();}}}