目录
PreparedStatement vs Statement
目录
PreparedStatement vs Statement
emm可能一篇不够,别当真......^v^
还差点案例肝不动了,我先往后学
引言
JDBC的作用(看不懂就往下,下面学完自然就懂了)
- 数据库连接:JDBC允许Java应用程序与数据库建立连接。通过使用JDBC技术我们可以建立与关系型数据库(如MySQL、Oracle、SQL Server等)或非关系型数据库(如MongoDB)的连接。
- SQL语句执行:JDBC提供了执行SQL语句的能力。
-
事务管理:JDBC支持事务的处理。我们可以使用JDBC开启、提交或回滚事务,
-
数据库元数据访问:通过JDBC,我们可以获取数据库的元数据信息(表、列、索引、约束等)。
-
结果集处理:JDBC允许我们检索和处理查询结果集。
-
预编译和存储过程:JDBC支持预编译SQL语句和执行数据库存储过程。
-
异常处理和错误检查:JDBC提供异常处理机制,允许捕获和处理与数据库交互过程中可能发生的错误和异常。
简单讲就是:Java开发人员可以从应用程序中使用Java代码直接连接到数据库,并执行各种数据库操作。
JDBC的历史和发展(内容来自chat GPT)(了解)
下面是JDBC的历史和发展的简要解释:
早期数据库连接:在Java出现之前,访问数据库的主要方式是使用各种数据库厂商提供的特定数据库API。这导致了编写和维护针对不同数据库的代码的复杂性,缺乏统一性。
JDBC的诞生:为了解决数据库访问的标准化问题,Sun Microsystems(当时的Java的维护者)在1997年推出了JDBC 1.0版本。JDBC(Java数据库连接)提供了一个统一的接口,使得Java应用程序可以通过相同的API与不同的数据库进行交互,无论是关系型数据库还是非关系型数据库。
JDBC的发展:随着Java的发展和数据库技术的进步,JDBC也经历了一系列的版本迭代和改进。每个JDBC版本都带来了新的功能和改进,以提高性能、简化开发,并支持新的数据库功能。
JDBC 2.0:在1998年发布,引入了一些重要的功能,如批量更新、行集、Scrollable ResultSet等。
JDBC 3.0:在2001年发布,提供了更多的数据类型支持、保存点(Savepoints)、数据库元数据访问等功能。
JDBC 4.0:在2006年随Java SE 6发布,主要的改进是自动加载驱动程序、更简化的连接管理、更好的异常处理等。
JDBC 4.1和4.2:在2011年和2013年发布,带来了一些小的增强和改进,如基于新日期和时间API的支持、更好的LOB(Large Object)支持等。
JDBC 4.3:在2017年发布,引入了对Java 8之后的新特性的支持,如流式处理、日期/时间API的增强等。
JDBC的生态系统:除了JDBC API本身,还有许多第三方库和框架,如连接池、ORM(对象关系映射)工具等,以帮助简化JDBC的使用和提高性能。
总的来说,JDBC从其推出以来,为Java开发人员提供了一种方便、灵活和标准的方式来连接和操作各种数据库。随着时间的推移,JDBC不断改进和丰富,适应了不断发展的数据库技术和Java平台的变化。
1、JDBC概述
定义(最好自己学完自己总结:什么是JDBC?)
JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。
比较高级的定义为:
JDBC是Java与数据库之间的桥梁。它提供了一种标准的方式来连接和操作数据库,使应用程序能够执行SQL查询、更新数据库、管理事务以及处理结果集等操作。
2、JDBC体系结构
-
JDBC API
JDBC API是整个架构的核心,它定义了与数据库交互的标准接口和操作方法。
面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。
jdbc 驱动(知道什么在JDBC中驱动是什么就行)
JDBC是由java官方为连接不同数据库提供的统一的接口(规范),但官方并没有提供各大数据库的实现类,而是不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。
总结驱动:JDBC 驱动程序是实现JDBC API的具体类或jar文件,它们提供了特定数据库的驱动程序代码。
为什么JDBC只有接口,没有提供实现?
不同数据库的底层技术不同,不少数据库是闭源的,源代码不公开的。Sun公司无力为所有数据库提供具体实现,只能提供接口而由数据库厂商提供具体实现,Sun公司只是制定JDBC标准,各个厂商准守标准提供具体的实现。JDBC和数据库实现的关系就好比List接口和ArrayList、LinkedList之间的关系。
原文链接:https://blog.csdn.net/weixin_40055163/article/details/120762277
jdbc 驱动程序共有四种类型:
- JDBC网路协议的纯Java驱动程序: 使用最多的类型
- JDBC-ODBC 桥
- 部分本地API,部分Java的驱动程序
- 本地协议的纯java驱动程序
3、JDBC连接数据库
数据库的连接步骤:
1、导入jar包
2、注册驱动
3、获取连接
4、获取执行者对象
5、执行sql语句,并接收返回结果
6、处理结果
7、释放资源
如何下载和导入jar包请移步:JDBC—jar包的下载与导入
JDBC技术相关接口和工具类:
接口 | 作用 |
---|---|
Driver | 驱动接口,定义建立链接的方式(接口) |
DriverManager | 工具类,用于管理驱动,可以获取数据库的链接 |
Connection | 表示Java与数据库建立的连接对象(接口) |
PreparedStatemen | 发送SQL语句的工具(接口) |
ResultSet | 结果集,用于获取查询语句的结果(接口) |
Driver接口介绍(了解)
-
java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
-
在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。
-
Oracle的驱动:oracle.jdbc.driver.OracleDriver
-
mySql的驱动: com.mysql.jdbc.Driver
-
1、DriverManager:DriverManager是JDBC的入口点,它负责加载适当的数据库驱动程序,并提供创建数据库连接的功能。可以通过调用getConnection
方法来获取数据库连接。该类主要进行如下功能:
- 注册驱动(告诉程序该使用哪一个数据库驱动) static void registerDriver(Driver driver) (DriverManager的方法)
static void registerDriver(Driver driver)
- 获取数据库连接(获取到数据库的连接并返回连接对象)
static Connection getConnection(String url, String user, String password)
//1、注册驱动/加载驱动
DriverManager.registerDriver(new Driver());
//2、获取连接connection
Connection connection = DriverManager.getConnection("jdbc:mysql//127.0.0.1:3306/girls", "root", "root");
2、Connection:表示应用程序与数据库之间的通信通道。通过JDBC连接,应用程序可以向数据库发送SQL语句,并接收和处理数据库返回的结果。
- 获取执行的对象(Statement/PreparedStatement):
获取普通执行对象:Statement createStatement();
获取预编译执行对象:PreparedStatement prepareStatement(String sql);
- 管理事务:
- 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
- 提交事务:commit();
- 回滚事务:rollback();
- 释放资源:
立即将数据库连接对象释放:void close();
3、Statement(知道怎么用就行了):用于执行SQL语句。Statement对象可以执行查询语句(ResultSet),也可以执行更新语句(如插入、更新和删除)。
- 执行DML语句:
参数sql:可以执行insert、update、delete语句。
int executeUpdate(String sql);
int executeInsert(String sql);
int executeDelete(String sql);
返回值int:返回影响的行数。
- 执行DQL语句:
ResultSet executeQuery(String sql);
返回值ResultSet:封装查询的结果。
参数sql:可以执行select语句。
- 释放资源
void close();
PreparedStatemen(重点掌握)
是Statement接口下的子接口,它代表一条预编译过的子接口,允许事先编译SQL语句,然后在多次执行时进行参数替换。这可以提高执行效率,并防止SQL注入攻击。在具有动态参数的地方可以用?代替。
SetXXX(int index, XXX xxx)来设置?替代的参数
PreparedStatement vs Statement
- PreparedStatement能最大可能的提高性能
数据库服务会对预编译的语句提供性能优化。因为预编译的语句可能被重复调用,所以语句在被编译器编译后的执行代码缓存下来,下次调用只要是相同预编译语句就不需要在编译,只需要将参数直接传入编译过的语句中就会得到执行。
statement语句中,即使是相同的操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义
- PreparedStatement可以防止SQL注入
Sql注入xiu案例:
假设有一个网站,用户可以通过用户名和密码登录。网站使用以下SQL语句来验证用户的凭据:
SELECT * FROM users WHERE username='[输入的用户名]' AND password='[输入的密码]'
攻击者通过在用户名输入框中输入恶意的SQL代码来实施注入攻击。例如,他们在用户名输入框(密码框中也行)中输入 '
OR
'1
'=
'1
'--(注意OR前的
')
,则会修改SQL语句为//(看出原因没username = ' ' OR '1'='1' --') SELECT * FROM users WHERE username= '' OR '1'='1' --' AND password='[输入的密码]'
在这种情况下,'
1
'=
'1
'始终为真,条件变为真,绕过了密码验证部分的检查,从而成功登录到了系统。攻击者可以使用各种技术和恶意代码来执行未经授权的操作,例如查询、修改或删除数据库中的数据,甚至获取管理员权限。
利用PreparedStatement 我们就可以防止这样的事情发生,因为预编译 会将要用户输入的部分的sql用?代替,如:
SELECT * FROM users WHERE username= ? AND password= ?
它已经预编译过了(就是告诉程序我长上面那样),只需要将?替换为用户输入的内容,而现在程序也知道了用户输入的哪部分了,无法在玩文字游戏了 。
4、ResultSet
- ResultSet:用于表示查询返回的数据集
判断结果集中是否还有数据:boolean next();
有数据返回true,并将索引向下移动一行
没有数据返回false
- 获取结果集中的数据:XXX getXxx(“列名”);
XXX代表数据类型(要获取某列数据,这一列的数据类型)
例如:String getString(“name”); int getInt(“age”);
- 释放资源
void close();
5、ResultSetMetaData
-
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
-
ResultSetMetaData meta = rs.getMetaData();
-
getColumnName(int column):获取指定列的名称
-
getColumnLabel(int column):获取指定列的别名
-
getColumnCount():返回当前 ResultSet 对象中的列数。
-
getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
-
getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
-
isNullable(int column):指示指定列中的值是否可以为 null。
-
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。
-
Java与SQL对应数据类型转换表
Java类型 | SQL类型 |
---|---|
boolean | BIT |
byte | TINYINT |
short | SMALLINT |
int | INTEGER |
long | BIGINT |
String | CHAR,VARCHAR,LONGVARCHAR |
byte array | BINARY , VAR BINARY |
java.sql.Date | DATE |
java.sql.Time | TIME |
java.sql.Timestamp | TIMESTAMP |
JDBC API 使用路线
- 静态SQL路线(没有动态值的语句)
DriverManager ->Connection -> Statement ->ResultSet
- 预编译SQL路线(有动态值的语句)常用
DriverManager ->Connection -> PreparedStatement->ResultSet
- 执行标准存储过程SQL路线
DriverManager ->Collection -> CallableStatement->Result
入门案例:
说明:JDBC的连接方式有很多,在开发中也主要掌握一种,避免白雪,前面的案例主要是帮助后面的理解
准备数据库
DROP TABLE IF EXISTS `beauty`;
CREATE TABLE `beauty` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`sex` char(1) DEFAULT '女',
`borndate` datetime DEFAULT '1987-01-01 00:00:00',
`phone` varchar(11) NOT NULL,
`photo` blob,
`boyfriend_id` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3;
/*Data for the table `beauty` */
insert into `beauty` values (1,'柳岩','女','1988-02-03 00:00:00','18209876577',NULL,8),(2,'苍老师','女','1987-12-30 00:00:00','18219876577',NULL,9),(3,'Angelababy','女','1989-02-03 00:00:00','18209876567',NULL,3),(4,'热巴','女','1993-02-03 00:00:00','18209876579',NULL,2),(5,'周冬雨','女','1992-02-03 00:00:00','18209179577',NULL,9),(6,'周芷若','女','1988-02-03 00:00:00','18209876577',NULL,1),(7,'岳灵珊','女','1987-12-30 00:00:00','18219876577',NULL,9),(8,'小昭','女','1989-02-03 00:00:00','18209876567',NULL,1),(9,'双儿','女','1993-02-03 00:00:00','18209876579',NULL,9),(10,'王语嫣','女','1992-02-03 00:00:00','18209179577',NULL,4),(11,'夏雪','女','1993-02-03 00:00:00','18209876579',NULL,9),(12,'赵敏','女','1992-02-03 00:00:00','18209179577',NULL,1);
案例1:
public class testConnection1 {
public static void main(String[] args) throws SQLException {
//1、注册驱动/加载驱动
Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
DriverManager.registerDriver(driver);//此句可以被注释掉
//2、获取连接connection
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/girls", "root", "root");
//3、获取执行者 statement
Statement statement = connection.createStatement();
//4、执行sql,获取结果集
String sql = "select * from beauty";
ResultSet resultSet = statement.executeQuery(sql);
//5、操作数据
while (resultSet.next())
{
System.out.println(resultSet.getInt("id") + "" + resultSet.getString("name"));
}
connection.close();
statement.close();
resultSet.close();
}
}
案例2:
public class testConnection2{
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加上导入jar包则为七个步骤
//1、加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/girls", "root", "root");
//3、获取执行对象
Statement statement = connection.createStatement();
//4.执行sql语句,获取结果集
String sql = "Select * from beauty";
ResultSet resultSet = statement.executeQuery(sql);
//5、处理结果
while (resultSet.next()) {
System.out.println(resultSet.getInt("id") +"\t"+ resultSet.getString("name"));
}
//6、释放资源
connection.close();
statement.close();
}
}
我们在第二个的入门案例中并没有注册驱动,也成功了,为什么呢????
因为我们使用了Class.forName:Class.forName(“com.mysql.jdbc.Driver”) 我们通过了给forName指定了是mysql的驱动,它会帮助我们注册驱动
在com.mysql.jdbc.Driver类中存在静态代码块(通过查看源码发现)
//这是com.mysql.jdbc.Driver的静态代码块,只要使用这个类,就会执行这段代码
//而Class.forName("com.mysql.jdbc.Driver")就正好使用到了这个类
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
注意:我们不需要通过DriverManager调用静态方法registerDriver(),因为只要Driver类被使用,则会执行其静态代码块完成注册驱动mysql5之后可以省略注册驱动的步骤。在jar包中,存在一个java.sql.Driver配置文件,文件中指定了com.mysql.jdbc.Driver
所以后边我们其实可以省略注册驱动的步骤(可以注释掉上个案例的注册驱动的步骤,也可以查询到数据)
案例三
提取工具类,将来我们可能会多次进行数据库的连接操作,而上述的连接操作都是重复多的,作为程序员只要有重复的代码就要减少它(虽然头发也可能随着emmmm.....)
下面的案例利用了配置文件,我们在更改数据库或者密码时就不需要在代码中找了,直接在配置文件中进行修改就行
配置文件
driverClass = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/girls
username = root
password = root
编写工具类
public class JDBCUtils {
public JDBCUtils() {
}
private static String driverClass;
private static String url;
private static String username ;
private static String password ;
private static Connection conn;
static {
try {
//两种写法
/*InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("JDBCUtils.properties");*/
InputStream is = ClassLoader.getSystemResourceAsStream("girlDatabase.properties");
Properties properties = new Properties();
properties.load(is);
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driverClass);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
//获取连接的方法
public static Connection getConnection(){
try {
conn = DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//5.释放资源的方法
public static void close(Connection conn, Statement stat, ResultSet rs) {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
进行测试:
在整个测试中,使用PreparedStatement
public class jdbcTest {
public static void main(String[] args) throws SQLException {
//1、获取连接
Connection connection = JDBCUtils.getConnection();
//2、获取执行对象,执行sql语句
String sql = " SELECT name, borndate , phone FROM beauty WHERE name = ? ";
PreparedStatement pre = connection.prepareStatement(sql);
//获取用户输入
System.out.println("请输入你的女神的姓名:");
Scanner sc = new Scanner(System.in);
String name = sc.next();
//给?更改为用户的输入
pre.setString(1, name);
//获取结果集
ResultSet re = pre.executeQuery();
System.out.println("信息为:");
//操作结果集中的内容
while (re.next()) {
System.out.println(re.getString("name") + " " + re.getDate("borndate") + " " + re.getString("phone"));
}
//利用 JDBCUtils关闭资源
JDBCUtils.close(connection,pre,re);
}
}
4、使用连接池管理连接
为什么使用连接池?
1、传统的JDBC连接的步骤:建立连接、执行sql语句、关闭连接。每一次数据库连接都需要建立和关闭连接,这样的方式会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重发利用
2、数据库连接建立之后都需要关闭,如果在执行操作期间出现异常未能关闭,将会导致数据库系统的内存泄露(数据库内存泄露:数据库进程占用内存不会被释放,导致内存持续增长,最终导致系统性能下降甚至崩溃)
3、不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,连接过多也可能导致内存泄露,服务器崩溃
连接池基本思想(可以尝试自己写一个连接池)
数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
数据库连接池在初始化时创建由最小数据库连接数决定的连接对象,无论是否被使用,连接池都保证至少拥有这么多连接对象的数量
最大数据库连接数量规定连接池最多能由多少连接数,如果申请超过最大连接池数,则这些请求将被加入到等待队列中。
使用连接池的优点:
提高性能和效率:数据库连接的创建和销毁是一项开销较大的操作。连接池会在系统启动时创建一定数量的连接对象,并在需要时重复利用这些连接,避免了频繁地创建和销毁连接的开销,从而提高了数据库访问的性能和效率。
提升并发处理能力:数据库连接池可以管理一定数量的连接对象,并使其可供并发的应用程序使用。当有多个并发请求时,连接池可以提供空闲的连接对象,避免了请求之间的等待,从而提升了系统的并发处理能力。
资源利用率提高:通过连接池,可以限制系统中连接的数量。这样可以避免过多的连接请求导致数据库资源的过度占用。连接对象的复用也可以减少系统资源的浪费,提高了资源利用率。
连接管理和监控:数据库连接池可以提供连接的管理和监控功能。它可以检查连接的可用性,避免使用已断开或失效的连接。连接池还可以记录连接的使用情况和状态,方便跟踪和排查连接问题,提高系统的可靠性和稳定性。
容错和恢复能力:在使用连接池的情况下,如果一个连接发生异常或超时,连接池可以关闭该连接,并创建一个新的连接对象来代替。这可以提高系统的容错和恢复能力,确保数据库访问的连续性。
多种开源的数据库连接池介绍
-
JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:
-
DBCP 是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。
-
C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以。hibernate官方推荐使用
-
Proxool 是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
-
BoneCP 是一个开源组织提供的数据库连接池,速度快
-
Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快
-
-
DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池
-
DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度。
-
特别注意:
-
数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。
-
当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但conn.close()并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。
-
这里我们主要介绍我们的国之光!!!
Druid(德鲁伊)数据库连接池
吹一下它
Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的连接池之一。
案例四(第一版)
使用的第一步就是先将它的jar包导入
创建一个lib文件夹(将下载的jar包导入)
添加成功后会出现一个小箭头>
创建一个druid.properties(如果properties放在同一个包下会无法找到,可以尝试新建一个resource文件和src在同一目录下)
点击idea左上角的File:
druid.properties的内容:
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/girls
username = root
password = root
和之前创建工具类类似,建立DuidUtils工具类(当然你可以用其他命名)
public class DruidUtils {
//连接池对象
private static DataSource dataSource = null ;
//初始化连接池对象
static{
//首先获取输入流
InputStream is = ClassLoader.getSystemResourceAsStream("druid.properties");
Properties pro = new Properties();
//读取配置文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取dataSource
try {
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
//提供对外连接的方法
public static Connection getConnection() throws SQLException {
//熟悉的步骤:获取连接(connection)
Connection connection = dataSource.getConnection();
return connection ;
}
//提供回收的方法
public static void freeConnection(Connection connection, Statement stat, ResultSet rs) {
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
利用上面的工具类连接数据库
public class TestDruid01 {
public static void main(String[] args) throws SQLException {
Connection conn = DruidUtils.getConnection();
String sql = "select id , name from beauty where name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
System.out.println("请输入你的姓名:");
Scanner sc = new Scanner(System.in);
String name = sc.next();
ps.setString(1 , name);
ResultSet re = ps.executeQuery();
System.out.println("信息为:");
while (re.next())
{
System.out.println(re.getInt("id") +"\t"+ re.getString("name") );
}
DruidUtils.freeConnection(conn , ps , re);
}
}
案例四(第一版)结束
案例四(第二版,线程版本...让我在理解理解,后序补上)
在我们利用三层架构设计时,
三层架构是一种常用的软件设计架构模式,它将软件系统划分为表示层(Presentation Layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data Access Layer)三个独立的层次。
5、Apache-DBUtils实现CRUD操作
CRUD是啥不知道了吧,哈哈^v^
CRUD代表创建(Create)、读取(Read)、更新(Update)和删除(Delete)
Apache DBUtils 是 Apache 组织提供的一个开源项目,它是一个用于简化 JDBC 编程的工具库。DBUtils 封装了一系列的 JDBC 操作,提供了简洁易用的 API,使得开发者可以更轻松地进行数据库访问和操作。
DBUtils 的主要特点如下:
简化的 API:DBUtils 提供了一组简化的 API,摒弃了繁琐的 JDBC 编程,使得数据库的访问和操作更加简洁和易于理解。
基本 CRUD 操作支持:DBUtils 提供了常见的增删改查操作的封装,开发者只需通过简单的 API 调用就能完成对数据库的操作。
集成了连接池:DBUtils 默认集成了 DBCP 连接池,可以轻松实现数据库连接的池化管理,提高了数据库访问的性能和效率。
支持 Bean 和 Map 的映射:DBUtils 提供了灵活的结果集映射机制,可以将数据库查询结果映射为 Java 对象(Bean)或者 Map 数据结构。
支持事务处理:DBUtils 提供了事务管理的支持,允许开发者通过 API 控制事务的提交和回滚,保证数据的一致性和完整性。
使用 DBUtils 可以大大简化 JDBC 编程的复杂度,减少了重复的代码编写,并提供了连接池和事务处理等功能,同时性能表现优异。
-
API介绍:
-
org.apache.commons.dbutils.QueryRunner
-
org.apache.commons.dbutils.ResultSetHandler
-
工具类:org.apache.commons.dbutils.DbUtils
-
工具类DbUtils
提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。
public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。
public static void commitAndClose(Connection conn)throws SQLException: 用来提交连接的事务,然后关闭连接
public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。
public static void rollback(Connection conn)throws SQLException:允许conn为null,因为方法内部做了判断
public static void rollbackAndClose(Connection conn)throws SQLException
rollbackAndCloseQuietly(Connection)
public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner 类
该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
QueryRunner类提供了两个构造器:
默认的构造器
需要一个 javax.sql.DataSource 来作参数的构造器
QueryRunner类的常用的方法:
更新
public int update(Connection conn, String sql, Object... params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。
插入
public <T> T insert(Connection conn,String sql,ResultSetHandler<T> rsh, Object... params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值
批处理
public int[] batch(Connection conn,String sql,Object params)throws SQLException: INSERT, UPDATE, or DELETE语句
public <T> T insertBatch(Connection conn,String sql,ResultSetHandler<T> rsh,Object params)throws SQLException:只支持INSERT语句
查询
public Object query(Connection conn, String sql, ResultSetHandler rsh,Object... params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
ResultSetHandler接口及实现类
-
该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。
-
ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。
-
接口的主要实现类:
-
ArrayHandler:把结果集中的第一行数据转成对象数组。
-
ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
-
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
-
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
-
ColumnListHandler:将结果集中某一列的数据存放到List中。
-
KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
-
MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
-
MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
-
ScalarHandler:查询单个值对象
-
案例稍等
注意事项(了解):
-
避免过度频繁的连接操作:连接数据库是一种资源密集型操作,频繁地打开和关闭连接会导致性能下降。应该尽量减少连接操作的次数,而是通过连接池等方式复用连接,提高系统性能。
-
使用预编译语句:预编译语句(PreparedStatement)可以提高数据库查询的性能。它使用占位符,将SQL语句和参数分离,减少了SQL解析的开销,并提供了防止SQL注入的安全性。
-
适当处理异常和关闭资源:在使用JDBC时,需要适当地处理异常和关闭资源。确保在代码中使用try-catch-finally块,及时释放数据库连接、语句和结果集等资源,避免资源泄漏和不必要的开销。
-
使用事务管理:对于需要保证数据一致性和可靠性的操作,应该使用事务管理来确保数据库操作的原子性、一致性、隔离性和持久性。通过使用JDBC的事务管理API,可以实现对事务的控制。
-
合理设计SQL语句:在编写SQL语句时,应该考虑数据库的索引、关联查询等因素。选择合适的索引和编写优化的SQL语句,可以提高数据库查询和更新操作的性能。
-
安全性考虑:在构建动态SQL语句时,应避免使用字符串拼接的方式,以防止SQL注入攻击。可以使用预编译语句或者参数化查询来确保输入的安全性。
总结
主要内容:
- DriverManager:JDBC的入口点,用于获取数据库连接。
- Connection:表示与数据库的连接,用于发送SQL语句和接收结果。
- Statement和PreparedStatement:用于执行静态SQL语句,执行数据库查询和更新操作。
- ResultSet:存储查询结果集,提供了对查询结果的访问和操作。
- CallableStatement:用于执行数据库中的存储过程。
- Metadata:提供了关于数据库和查询结果的元数据信息,如表结构、列名等。
- 事务管理:提供了控制和管理数据库事务的功能,确保数据的一致性和可靠性。
应用场景:
-
数据库查询和更新:通过JDBC可以执行各种数据库查询和更新操作,如数据检索、插入、修改和删除等。
-
数据库事务管理:使用JDBC可以控制和管理数据库事务,确保数据的一致性和完整性,在多个操作之间进行原子性控制。
-
数据库连接池:JDBC可以与连接池配合使用,提高数据库连接的性能和效率。
-
数据库连接和资源的管理:使用JDBC可以在应用程序中管理数据库连接和资源的创建、使用和释放。这包括了关闭连接、释放资源、错误处理等操作,保证了程序的正确性和稳定性。
-
数据库元数据的获取:通过JDBC可以获取数据库的元数据信息,如表结构、列名、约束等,方便进行动态的数据访问和操作。