JDBC笔记
一、jdbc的下载,网址为[ https://www.mysql.com/]
二、JDBC的使用
1.jdbc的初次使用
代码
package com.leon.study; import com.mysql.jdbc.Driver; import org.junit.jupiter.api.Test; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; /**
ClassName:HelloWord
Package:com.leon.study
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/23 10:14
@Version: 1.0
*/
public class HelloWord {
@Test
public void studyJdbc() throws Exception {
// 注册驱动驱动Driver driver = new Driver();
// 获取连接
/* 1.jdbc:mysql这个表示的是协议,通过jdbc的方式连接MYSQL 2.localhost 指的是ip地址 3.3306 指的是端口号 4.studyjdbc 指的是你要连接的数据库名称 */ String url = "jdbc:mysql://localhost:3306/studyjdbc"; Properties properties = new Properties();
// 数据库用户名
properties.setProperty("user","root");
// 数据库用户密码
properties.setProperty("password","root"); Connection connect = driver.connect(url, properties);
// System.out.println(connect);
// 执行sql语句
// 创建SQL语句String sql = "insert into actor values(null,'李华','女','1991-7-8','985211')"; Statement statement = connect.createStatement();
// 执行SQL语句‘
int i = statement.executeUpdate(sql); System.out.println(i);
// 关闭资源
if(statement != null){ statement.close(); } if(connect != null ){ connect.close(); }
}
}
2.jdbc的获取连接的五种方式
package com.leon.connect; import com.mysql.jdbc.Driver; import org.junit.jupiter.api.Test; import java.io.FileInputStream; import java.lang.reflect.Constructor; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.util.Properties; /** * ClassName:ConnectTest * Package:com.leon.connect * Description: * * @Author: leon-->ZGJ * @Create: 2023/11/23 10:42 * @Version: 1.0 */ public class ConnectTest { // 方式一 @Test public void connect01() throws Exception { // 注册驱动 Driver driver = new Driver(); // 建立连接 String url = "jdbc:mysql://localhost:3306/studyjdbc"; Properties properties = new Properties(); properties.setProperty("user","root"); properties.setProperty("password","root"); Connection connect = driver.connect(url, properties); // 执行SQL语句 String sql = "insert into actor values(null,'刘德华','男','1998-12-1','110')"; Statement statement = connect.createStatement(); statement.executeUpdate(sql); // 关闭资源 if(statement != null){ statement.close(); } if(connect != null ){ connect.close(); } } // 方式二 @Test public void connect02() throws Exception { // 类加载 Class clazz = Class.forName("com.mysql.jdbc.Driver"); // 获取构造器 Constructor declaredConstructor = clazz.getDeclaredConstructor(); // 强制访问 declaredConstructor.setAccessible(true); // 创建对象 Driver driver = (Driver)declaredConstructor.newInstance(); String url = "jdbc:mysql://localhost:3306/studyjdbc"; Properties properties = new Properties(); // user和password是规定好,不能胡乱更改 properties.setProperty("user","root"); properties.setProperty("password","root"); Connection connect = driver.connect(url, properties); // 执行SQL语句 String sql = "insert into actor values(null,'韩老师','男','1998-12-1','110')"; // 获取Statement对象 Statement statement = connect.createStatement(); statement.executeUpdate(sql); } // 方式三 /* 1. 使用DriverManager对Driver进行统一管理 2. 使用 registerDriver()静态方法进行注册 */ @Test public void connect03() throws Exception { Class clazz = Class.forName("com.mysql.jdbc.Driver"); // 获取构造器 Constructor declaredConstructor = clazz.getDeclaredConstructor(); // 强制访问 declaredConstructor.setAccessible(true); // 创建对象 Driver driver = (Driver) declaredConstructor.newInstance(); // 使用DriverManager统一进行注册管理 DriverManager.registerDriver(driver); // 创建url、user、password String url = "jdbc:mysql://localhost:3306/studyjdbc"; String user = "root"; String password = "root"; // 获取连接 Connection connection = DriverManager.getConnection(url, user, password); // 创建SQL语句 String sql = "delete from actor where id = '3'"; // 获取Statement对象 Statement statement = connection.createStatement(); // 执行SQL语句 int i = statement.executeUpdate(sql); System.out.println(i > 0 ? "删除成功":"删除失败"); } // 方式4 @Test public void connect04() throws Exception { // 进行类的加载 Class.forName("com.mysql.jdbc.Driver"); // 因为Driver的静态代码块对Driver进行了注册管理 /* 1.代码 static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException var1) { throw new RuntimeException("Can't register driver!"); } } */ // 创建url、user、password String url = "jdbc:mysql://localhost:3306/studyjdbc"; String user = "root"; String password = "root"; Connection connection = DriverManager.getConnection(url, user, password); System.out.println(connection); } // 方式五 @Test public void connect05() throws Exception { // 进行类加载 Class.forName("com.mysql.jdbc.Driver"); // 使用文件来读取连接信息 Properties properties = new Properties(); // 加载文件 properties.load(new FileInputStream("src/mysql.properties")); // 获取数据 String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password"); // 获取connect连接 Connection connection = DriverManager.getConnection(url, user, password); System.out.println(connection); } }
3.ResultSet接口
基本介绍
表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
ResultSet对象维护一个指向其当前数据行的光标。最初,光标位于第一行之前。next方法将光标移到下一行,因为当ResultSet对象中没有更多行时,它会返回false,所以可以在while循环中使用它来迭代结果集。
previous()向上移动一行
getXxx(列的索引或者列名),这个xxx是你在数据库表设置的数据类型
getObject(列的索引值或列名),返回值对应列的值,接收类型为Object
代码
package com.leon.resultset; import org.junit.jupiter.api.Test; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; /**
ClassName:ResultSetTest
Package:com.leon.resultset
Description:
使用ResultSet类的使用
@Author: leon–>ZGJ
@Create: 2023/11/23 17:27
@Version: 1.0
*/
public class ResultSetTest {@Test
public void resultSet() throws Exception {
// 创建properties对象Properties properties = new Properties();
// 加载文件
properties.load(new FileInputStream("src/mysql.properties"));
// 获取数据:url,user,password,driver
String driver = properties.getProperty("driver"); String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password");
// 加载驱动
Class.forName(driver);
// 获取数据库链接
Connection connection = DriverManager.getConnection(url, user, password);
// 创建SQL语句
String sql = "select id,name,sex,borndate from actor";
// 获取Statement对象
Statement statement = connection.createStatement();
// 执行SQL语句
ResultSet resultSet = statement.executeQuery(sql); /* 表中的数据 +----+--------+-----+---------------------+--------+ | id | name | sex | borndate | phone |
next +—-+——–+—–+———————+——–+
—-> | 2 | 李华 | 女 | 1991-07-08 00:00:00 | 985211 || 4 | 刘德华 | 男 | 1998-12-01 00:00:00 | 110 | | 5 | 刘德华 | 男 | 1998-12-01 00:00:00 | 110 | | 6 | 韩老师 | 男 | 1998-12-01 00:00:00 | 110 | | 7 | 韩老师 | 男 | 1998-12-01 00:00:00 | 110 | +----+--------+-----+---------------------+--------+ */
// 如果没有更多行时返回false
while(resultSet.next()){
// 获取第一行第一列的数据
int id = resultSet.getInt(1);
// 获取第一行第二列的数据
String name = resultSet.getString(2);
// 获取第一行第三列的数据
String sex = resultSet.getString(3);
// 获取第一行第四列的数据
String borndate = resultSet.getString(4); System.out.println("id = " + id + " name= " + name + " sex= " + sex + " brondate= " + borndate); }
// 关闭资源
if(resultSet != null){ resultSet.close(); } if(statement != null){ statement.close(); } if(connection != null){ connection.close(); }
}
}
数据示意图
4.Statement接口
Statement对象用于执行静态SQL语句并返回生成的结果对象
在建立连接后,需要对数据库进行访问,执行SQL语句,可以通过
Statement[这个存在SQL注入问题]
PreparedStatement[预处理]
CallableStatement[存储过程]
Statement对象执行SQL语句,存在SQL注入风险,所以不建议使用
SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库
防范SQL注入,只要使用PreparedStatement(从Statement扩展而来)取代Statement就可以了
类图
Statement 代码
package com.leon.preparedstatement; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; import java.util.Scanner; /**
ClassName:StatementTest
Package:com.leon.preparedstatement
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/23 22:13
@Version: 1.0
*/
public class StatementTest {public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in); System.out.print("请输入你的账号:"); String name = scanner.nextLine(); System.out.print("请输入你的密码:"); String pwd = scanner.nextLine(); // 读取数据 Properties properties = new Properties();
// 加载文件
properties.load(new FileInputStream(StatementTest.class.getResource("/").getFile()+"mysql.properties"));
// 读取数据Driver,url ,user,password
String driver = properties.getProperty("driver"); String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password");
// 类加载
Class.forName(driver);
// 获取连接
Connection connection = DriverManager.getConnection(url, user, password);
// 获取select对象
Statement statement = connection.createStatement();
// 创建SQL语句
String sql = "select * from admin where name='"+name+"' and pwd = '"+pwd+"'";
// 执行SQL
ResultSet resultSet = statement.executeQuery(sql); if(resultSet.next()){ System.out.println("登录成功"); }else { System.out.println("登录失败"); }
// 关闭资源
if(resultSet != null){ resultSet.close(); } if(statement != null){ statement.close(); } if(connection != null){ connection.close(); }
}
}
5. PreparedStatement 类
基本介绍
PreparedStatement 执行的SQL语句中不确定的参数用 “?“(又称占位符) 来表示,调用PreparedStatement对象的setXxx(parameterIndex,xxx)方法来设置这些参数,setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的 占位符的索引(从1开始),第二个是设置SQL语句中的占位符的值,值的类型根据你在数据库中的表来确定的
调用executeQuery(),返回的是ResultSet对象,这个是查询语句使用的方法,也可说是执行DQL语句的方法:DQL语句:数据查询语句
调用excuteUpdate(),执行更新,包括增,删,修改,返回的是影响的行数,也可以说是执行DML语句的方法:DML语句:数据库操作语言
setObject(占位符索引值,占位符的值)
预处理好处
不再使用字符串拼接SQL语句,减少语法错误
有效的解决了SQL注入问题
大大减少了编译次数,效率较高
代码
package com.leon.preparedstatement; import org.junit.jupiter.api.Test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.sql.*; import java.util.Properties; import java.util.Scanner; /**
ClassName:PreparedStatementTest
Package:com.leon.preparedstatement
Description:
*@Author: leon–>ZGJ
@Create: 2023/11/23 21:52
@Version: 1.0
*/
public class PreparedStatementTest {public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in); System.out.print("请输入你的账号:"); String name = scanner.nextLine(); System.out.print("请输入你的密码:"); String pwd = scanner.nextLine(); // 读取数据 Properties properties = new Properties();
// 加载文件
properties.load(new FileInputStream(StatementTest.class.getResource("/").getFile()+"mysql.properties"));
// 读取数据Driver,url ,user,password
String driver = properties.getProperty("driver"); String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password");
// 类加载
Class.forName(driver);
// 获取连接
Connection connection = DriverManager.getConnection(url, user, password);
// 创建SQL
String sql = "select * from admin where name = ? and pwd = ? "; // 获取PreparedStatement对象 PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 给占位符设置数据
preparedStatement.setString(1,name); preparedStatement.setString(2,pwd);
// 执行语句,这个是不需要在executeQuery()方法中传入SQL语句作为实参,因为有占位符
ResultSet resultSet = preparedStatement.executeQuery(); if(resultSet.next()){ System.out.println("登录成功"); }else { System.out.println("登录失败"); } // 关闭资源 if(resultSet != null){ resultSet.close(); } if(preparedStatement != null){ preparedStatement.close(); } if(connection != null){ connection.close(); }
}
}
6. 事务
- 基本介绍
- jdbc程序中当一个Connection对象创建时,默认情况下是自动提交事务,每次执行一个SQL语句是,如果执行成功,就会向数据库自动提交,而不能回滚
- jdbc程序中为了让多个SQL语句作为一个整体执行,需要使用事务
- 调用Connection的setAutoCommit(false)可以取消自动提交事务
- 所有的SQL语句都成功执行后,调用commit()方法提交事务
- 在其中某个操作失败或出现异常时,调用rollback()方法回滚事务
7. 批处理
- 基本介绍
- 当需要成批插入或者更新记录时,可以采用java的批量更新机制,这一机制允许多条语句一次提交给数据库批量处理,通常情况下比单独提交处理更有效率
- JDBC的批量处理语句包括下面方法:
- addBatch():添加需要批量处理的SQL语句或参数
- executeBatch():执行批量处理语句
- clearBatch():清空批处理语句
- JDBC连接MYSQL时,如果要使用批处理功能,请在url中添加参数{?rewriteBatchedStatements=true}
- 批处理往往和PreparedStatement一起搭配使用,可以减少编译次数,又减少运行次数,效率大大提高
8.数据库连接池
- 数据库连接池基本介绍
- 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需要从“缓冲池”中取出一个,使用完毕之后再放回去
- 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
- 当应用程序向连接池请求的连接超过最大连接数量时,这些请求将被加入到等待队列中
- 数据库连接池种类
- JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现
- C3P0数据库连接池,速度相对较慢,稳定性不错(hibernate,spring底层使用的都是C3P0)
- DBCP数据库连接池,速度相对c3p0较快,但是不稳定
- Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
- BoneCP数据库连接池,速度快
- Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池
9.Apache-DBUtils
commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是JDBC的封装。使用dbutils能极大简化JDBC编码工作量
DBUtils类
QueryRunner类:该类封装了SQL的执行,是线程安全的,可以实现增、删、改、查、批处理
ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一个形式
对象
ArrayHandler:把结果集中的第一行数据转成对象数组 ArrayListHandler:把结果集中的每一行都转成一个数组,再存放到List中 BeanHandler:将结果集中的第一行数据封装到一个对应的javaBean实例中 BeanListHandler:将结果集中的每一行数据都封装到一个对应的javaBean实例中,存放到List里 ColumnListHandler:将结果集中的某一列的数据存放到List中 KeyedHandler(name):将结果集中的每一行都封装到Map里,再把这些map存放到一个map里,其key为指定的key MapHandler:将结果集中的第一行数据存放到一个Map里,key是列名,values就是对应的值 MapListHandler:将结果集中的每一行数据都封装到一个map里,然后再存放到List ScalarHandler:将某一行的某一列数据封装到Object对象中