JDBC
1、JDBC概述
-
JDBC概念
(1)JDBC 就是使用Java语言操作关系型数据库的一套API
(2)全称:( Java DataBase Connectivity ) Java 数据库连接
-
JDBC本质
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
-
JDBC好处
- 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
- 可随时替换底层数据库,访问数据库的Java代码基本不变
2、JDBC快速入门
-
导入驱动包
-
将驱动包放入lib目录(自己创建)
-
添加为库文件,设置有效范围
- Global Library : 全局有效
- Project Library : 项目有效
- Module Library : 模块有效
-
-
编写代码步骤
-- 创建工程,导入驱动jar包
-- 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
-- 2. 获取连接
Connection conn = DriverManager.getConnection(url, username, password);
-- 3. 定义SQL语句
String sql = “update…” ;
-- 4. 获取执行SQL对象
Statement stmt = conn.createStatement();
-- 5. 执行SQL
int count = stmt.executeUpdate(sql); -- 返回影响行数
-- 6. 处理返回结果
System.out.print(count);
-- 7. 释放资源
stmt.close();
conn.close();
public static void main(String[] args) throws Exception {
//1. 注册驱动
//Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 定义sql
String sql = "update account set money = 2000 where id = 1";
//4. 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
//5. 执行sql
int count = stmt.executeUpdate(sql);//受影响的行数
//6. 处理结果
System.out.println(count);
//7. 释放资源
stmt.close();
conn.close();
}
第一版JDBC使用操作,共七个步骤
3、JDBC API详解
- DriverManager
-
1.作用:
(1) 注册驱动
(2)获取数据库连接 -
2.注册驱动:registerDriver(Driver driver)
(1)DriverManager类中的静态代码块中已经执行了 DriverManagern对象的 registerDriver()n方法进行驱动的注册,只需要加载 Driver 类,该静态代码块就会执行
(2)MySQL 5之后的驱动包,可以省略注册驱动的步骤,自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
-
3.获取数据库连接:getConnection(string url,string user, string password)
(1)url : 连接路径
(2)user :用户名
(3)poassword :密码语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
示例:jdbc:mysql://127.0.0.1:3306/db1
细节:- 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
- 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
-
第二版JDBC使用操作,省略注册驱动步骤,剩六个步骤
-
Connection
- 作用
(1)获取执行 SQL 的对象
(2)管理事务 - 获取执行对象
// 三个方法 // (1)普通执行SQL对象 Statement createStatement() // (2)预编译SQL的执行SQL对象:防止SQL注入 PreparedStatement prepareStatement(sql) // (3)执行存储过程的对象 CallableStatement prepareCall(sql) //存储过程在MySQL中不常用
- 管理事务
// (1)开启事务 setAutoCommit(boolean autoCommit) //true为自动提交事务;false为手动提交事务,即为开启事务 // (2)提交事务 commit() // (3)回滚事务 rollback()
try { // ============开启事务========== conn.setAutoCommit(false); //5. 执行sql int count1 = stmt.executeUpdate(sql1);//受影响的行数 //6. 处理结果 System.out.println(count1); //5. 执行sql int count2 = stmt.executeUpdate(sql2);//受影响的行数 //6. 处理结果 System.out.println(count2); // ============提交事务========== //程序运行到此处,说明没有出现任何问题,则需求提交事务 conn.commit(); } catch (Exception e) { // ============回滚事务========== //程序在出现异常时会执行到这个地方,此时就需要回滚事务 conn.rollback(); e.printStackTrace(); }
- 作用
-
Statement
- 作用:执行SQL语句
- 执行DDL、DML语句:int executeUpdate(string sql)
- 执行DQL语句:ResultSet executeQuery(string sql)
-
ResultSet
- ResultSet(结果集对象)作用:封装了SQL查询语句的结果
- boolean next()
(1)将光标从当前位置向前移动一行 ,然后判断当前行是否为有效行
(2)true : 有效航,当前行有数据;false : 无效行,当前行没有数据 - xxx getXxx(参数)
(1)获取数据
(2)xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
(3)int类型的参数:列的编号,从1开始
(4)String类型的参数: 列的名称
// 3. 定义sql
String sql = "select * from account";
// 4. 获取statement对象
Statement stmt = conn.createStatement();
// 5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 6. 处理结果, 遍历rs中的所有数据
// 6.1 光标向下移动一行,并且判断当前行是否有数据
while (rs.next()){
// 6.2 获取数据 getXxx()
//数据格式:id[int] name[String] money[double]
//int id = rs.getInt(1);
//String name = rs.getString(2);
//double money = rs.getDouble(3);
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("--------------");
}
- PreparedStatement
-
PreparedStatement作用:预编译SQL语句并执行——预防SQL注入问题
-
SQL注入
(1)SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法
(2)例如:可以通过输入一些特殊的字符登陆到首页,用户名随意写,将密码写成' or '1' ='1
,这就是SQL注入漏洞 -
PreparedStatement的使用
// 1.获取 PreparedStatement 对象 // SQL语句中的参数值,使用?占位符替代 String sql = "select * from user where username = ? and password = ?"; // 通过Connection对象获取,并传入对应的sql语句 PreparedStatement pstmt = conn.prepareStatement(sql); // 2.设置参数值 setXxx(参数1,参数2) //Xxx:数据类型,如 setInt (参数1,参数2) //参数1: ?的位置编号,从1 开始 | 参数2: ?的值 // 3.执行SQL语句 executeUpdate(); // 执行DDL语句和DML语句 executeQuery(); // 执行DQL语句 //不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。
@Test public void testPreparedStatement() throws Exception { //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写 String url = "jdbc:mysql:///db1?useSSL=false"; String username = "root"; String password = "1234"; 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(); }
-
Java代码操作数据库流程
- 将sql语句发送到MySQL服务器端
- MySQL服务端会对sql语句进行如下操作
(1)检查SQL语句
(2)编译SQL语句。将SQL语句编译成可执行的函数
(3)执行SQL语句
-
PreparedStatement 好处
- 预编译SQL,性能更高
(1)检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能
(2)预编译功能默认关闭,需要主动开启
(3)开启预编译功能:编写url时加上useServerPrepStmts=true
- 防止SQL注入:将敏感字符进行转义
- 预编译SQL,性能更高
-
配置MySQL执行日志(重启mysql服务后生效)
在mysql配置文件(my.ini)中添加如下配置
日志文件的存放位置可自行更改(第三、五句)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
-
第三版JDBC使用操作,用PreparedStatement替换Statement,多了一个参数设置步骤,共七个步骤
4、数据库连接池
-
数据库连接池简介
- 介绍
(1)数据库连接池是个容器,负责分配、管理数据库连接(Connection)
(2)它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
(3)释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏 - 好处
(1)资源重用
(2)提升系统响应速度
(3)避免数据库连接遗漏
- 介绍
-
数据库连接池实现
- 标准接口:DataSource
(1)官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口
(2)该接口提供了获取连接的功能:Connection getConnection()
(3)以后就不需要通过DriverManager
对象获取Connection
对象,而是通过连接池(DataSource)获取Connection
对象 - 常见的数据库连接池
(1)DBCP
(2)C3P0
(3)Druid - Druid(德鲁伊)
(1)Druid连接池是阿里巴巴开源的数据库连接池项目
(2)功能强大,性能优秀,是Java语言最好的数据库连接池之一
- 标准接口:DataSource
-
Driud使用
-
使用步骤
- 导入jar包 druid-1.1.12.jar
- 定义配置文件
- 加载配置文件
- 获取数据库连接池对象
- 获取连接
-
导入jar包
-
定义配置文件
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true username=root password=1234 # 初始化连接数量 initialSize=5 # 最大连接数 maxActive=10 # 最大等待时间 maxWait=3000
-
//1.导入jar包
//2.定义配置文件
//3. 加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
//4. 获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5. 获取数据库连接 Connection
Connection connection = dataSource.getConnection();
System.out.println(connection); //获取到了连接后就可以继续做其他操作了
第四版JDBC使用操作,用连接池取代直接创建连接,还是七个步骤
5、案例代码
/**
* 查询所有
* 1. SQL: select * from tb_brand;
* 2. 参数:不需要
* 3. 结果:List<Brand>
*/
@Test
public void testSelectAll() throws Exception {
//1. 获取Connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2. 定义SQL
String sql = "select * from tb_brand;";
//3. 获取pstmt对象
PreparedStatement pstm = conn.prepareStatement(sql);
//4. 设置参数
//5. 执行SQL
ResultSet rs = pstm.executeQuery();
//6. 处理结果 List<Brand> 封装Brand对象,装载List集合
Brand brand = null;
List<Brand> brands = new ArrayList<>();
while (rs.next()){
//获取数据
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
//封装Brand对象
brand = new Brand();
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
//装载集合
brands.add(brand);
}
System.out.println(brands);
//7. 释放资源
rs.close();
pstm.close();
conn.close();
}