JAVA基础:JDBC的使用 附详细代码

Posted BudingCode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础:JDBC的使用 附详细代码相关的知识,希望对你有一定的参考价值。

JDBC使用大全

JDBC(Java DataBase Connectivity, java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序

基础概念

JDBC体系结构

通常,JDBC体系结构由两层组成:

  • JDBC API:这提供了应用程序到JDBC管理器连接。
  • JDBC驱动程序API:这支持JDBC管理器到驱动程序连接。

JDBC API使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接。

JDBC核心组件

  • DriverManager:此类管理数据库驱动程序列表。使用通信子协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。
  • Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用DriverManager对象来管理这种类型的对象。
  • Connection:该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库的所有通信仅通过连接对象。
  • Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派 生接口还接受参数。
  • ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一 个迭代器,允许我们移动其数据。
  • SQLException:此类处理数据库应用程序中发生的任何错误

相关步骤

构建应用程序的步骤

构建JDBC应用程序涉及以下六个步骤:

  • 导入包:需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够了。
  • 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
  • 打开连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表 示与数据库的物理连接。
  • 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
  • 从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。 - 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。

连接步骤

建立JDBC连接所涉及的编程相当简单。这是简单的四个步骤

  • 导入JDBC包:将Java语言的import语句添加到Java代码中导入所需的类。
  • 注册JDBC驱动程序:此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC 请求。
  • 数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库。
  • 创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连接。

注册驱动程序

最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册
DriverManager.registerDriver()

try 
   Class.forName("com.mysql.cj.jdbc.Driver");
catch(ClassNotFoundException ex) 
   System.out.println("Error: unable to load driver class!");
   System.exit(1);

第二种方法是使用静态DriverManager.registerDriver()方法,比较少用,这里就直接略过,有需要的同学可以自行查询。

数据库URL配置

加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。为了方便参考,让我
列出三个重载的DriverManager.getConnection()方法

  • getConnection(String url)
  • getConnection(String url,Properties prop)
  • getConnection(String url,String user,String password)
RDMBS
MYSQL8com.mysql.cj.jdbc.Driverjdbc:mysql://hostname:3306/databaseName?serverTimezone=UTC
MySQLcom.mysql.jdbc.Driverjdbc:mysql://hostname:3306/databaseName
ORACLEoracle.jdbc.driver.OracleDriverjdbc:oracle:thin:@hostname:port Number:databaseName
DB2COM.ibm.db2.jdbc.net.DB2Driverjdbc:db2:hostname:port Number / databaseName
SYBASEcom.sybase.jdbc.SybDriverjdbc:sybase:Tds:hostname:port Number / databaseName

创建数据库连接对象

String URL = "jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC";
String USER = "username";
String PASS = "password"
Connection conn = DriverManager.getConnection(URL, USER, PASS);

使用数据库URL和属性对象
DriverManager.getConnection()方法需要一个数据库URL和一个Properties对象

DriverManager.getConnection(String url, Properties info);
import java.util.*;
String URL = "jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC";
Properties info = new Properties( );
info.put( "user", "username" );
info.put( "password", "password" );
Connection conn = DriverManager.getConnection(URL, info);

关闭数据库连接

为确保连接关闭,您可以在代码中提供一个“finally”块。一个finally块总是执行,不管是否发生异常。 要关闭上面打开的连接,你应该调用close()方法:

conn.close();

执行SQL语句

一旦获得了连接,我们可以与数据库进行交互。JDBC Statement和PreparedStatement接口定义了使 您能够发送SQL命令并从数据库接收数据的方法和属性。

Statement 和 PreparedStatement

接口推荐使用
Statement用于对数据库进行通用访问。在运行时使用静态SQL语句时很有用。Statement接口不能 接受参数
PreparedStatement当您计划多次使用SQL语句时使用。PreparedStatement接口在运行时接受 输入参数。

Statement

创建语句对象
在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建 一个,如下例所示:

Statement stmt = null;
try 
   stmt = conn.createStatement( );
... 
catch (SQLException e)  ...
 finally 
... 

创建Statement对象后,您可以使用它来执行一个SQL语句,其中有三个执行方法之一。

  • boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true;否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
  • int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
  • ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使
    用此方法,就像使用SELECT语句一样

关闭Statement对象
就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。

一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭Statement对 象。但是,应始终显式关闭Statement对象,以确保正确清理。

Statement stmt = null;
try 
   stmt = conn.createStatement( );
... 
catch (SQLException e)  ...
 finally 
   stmt.close();

PreparedStatement

该PreparedStatement的接口扩展了Statement接口,它为您提供了一个通用的Statement对象有两个优点附加功能。
此语句使您可以动态地提供参数。

PreparedStatement pstmt = null;
try 
	String SQL = "Update Employees SET age = ? WHERE id = ?"; 
	pstmt = conn.prepareStatement(SQL);
...

catch (SQLException e) 
... 
finally  ...

JDBC中的所有参数都由 ? 符号,这被称为参数标记。

在执行SQL语句之前,必须为每个参数提供值。 所述的setXXX()方法将值绑定到所述参数,其中XXX代表要绑定到输入参数的值的Java数据类型。如果忘记提供值,将收到一个SQLException。

每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。该方法与Java数组索引不同,从0开始。

关闭PreparedStatement对象
就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象。

一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭 PreparedStatement对象。但是,应始终显式关闭PreparedStatement对象,以确保正确清理。

   pstmt.close();

PreparedStatement批处理

  1. 使用占位符创建 SQL 语句
  2. 使用prepareStatement() 方法创建 PrepareStatement 对象
  3. 使用setAutoCommit()将 auto-commit 设置为 false
  4. 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中
  5. 在创建的语句对象上使用 executeBatch() 方法执行所有SQL语句
  6. 最后,使用commit() 方法提交所有更改

Statement和PreparedStatement的区别

  • statement属于状态通道,PreparedStatement属于预状态通道
  • 预状态通道会先编译sql语句,再去执行,比statement执行效率高
  • 预状态通道支持占位符?,给占位符赋值的时候,位置从1开始
  • 预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理

类型 描述

ResultSet.TYPE_SCROLL_INSENSITIVE
光标可以向前和向后滚动,结果集对创建结果集后发生
的数据库的其他更改不敏感。
ResultSet.TYPE_SCROLL_SENSITIVE。
光标可以向前和向后滚动,结果集对创建结果集之后发
生的其他数据库所做的更改敏感。
ResultSet.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动。

ResultSet

SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示结果集数据库查询。

ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数 据。

如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。

类型描述
ResultSet.TYPE_SCROLL_INSENSITIVE光标可以向前和向后滚动,结果集对创建结果集后发生的数据库的其他更改不敏感。
ResultSet.TYPE_SCROLL_SENSITIVE光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感。
ResultSet.TYPE_FORWARD_ONLY光标只能在结果集中向前移动。
try 
   Statement stmt = conn.createStatement(
							ResultSet.TYPE_FORWARD_ONLY,
							ResultSet.CONCUR_READ_ONLY);
catch(Exception ex) 
   ....
finally 
   ....

数据库事务

一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个执行单元。

事务概述

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错,恢复并使应用程序更加可靠。
一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务 的处理。

事务开始于

  • 连接到数据库上,并执行一条DML语句insert、update或delete - 前一个事务结束后,又输入了另一条DML语句

事务结束于

  • 执行commit或rollback语句。
  • 执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。 - 执行一条DDL语句,例如grant语句,在这种情况下,会自动执行commit。
  • 断开与数据库的连接
  • 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语 句。

事务的四大特点

  • actomicity(原子性)
    表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
  • consistency(一致性)
    表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
  • isolation(隔离性)
    事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
  • durability(持久性)
    持久性事务完成之后,它对于系统的影响是永久性的。

JDBC中事务应用

如果JDBC连接处于自动提交模式,默认情况下,则每个SQL语句在完成后都会提交到数据库。
事务使您能够控制是否和何时更改应用于数据库。它将单个SQL语句或一组SQL语句视为一个逻辑单 元,如果任何语句失败,则整个事务将失败。
要启用手动事务支持,而不是JDBC驱动程序默认使用的自动提交模式,请使用Connection对象的 setAutoCommit()方法。如果将boolean false传递给setAutoCommit(),则关闭自动提交。我 们可以传递一个布尔值true来重新打开它。

事务的提交和回滚

完成更改后,我们要提交更改,然后在连接对象上调用commit()方法,如下所示:

conn.commit( );

否则,要使用连接名为conn的数据库回滚更新,请使用以下代码 -

conn.rollback( );

Savepoints
新的JDBC 3.0 Savepoint接口为您提供了额外的事务控制。 设置保存点时,可以在事务中定义逻辑回滚点。如果通过保存点发生错误,则可以使用回滚方法来撤消所有更改或仅保存在保存点之后所做的更改。

Connection对象有两种新的方法来帮助您管理保存点

  • setSavepoint(String savepointName):定义新的保存点。它还返回一个Savepoint对象。
  • releaseSavepoint(Savepoint savepointName):删除保存点。请注意,它需要一个Savepoint 对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。

连接池

数据连接池原理:
连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。

自定义连接池

我们可以通过自定义的方式实现连接池,分析连接池类应该包含特定的属性和方法

  • 属性: 集合 放置Connection
  • 方法: 获取连接方法
    回收连接方法

具体实现代码:

public class Pool
static LinkedList<Connection> list  = new LinkedList<Connection>();
    static
        for (int i = 0; i < 10; i++) 
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.add(connection);
 
/**
* 从连接池子中获取连接的方式 * @return
*/
    public static Connection getConnection()
if (list.isEmpty()) 
//JDBCUtils类是自定义类,封装了连接数据库的信息代码
Connection connection = JDBCUtils.newInstance().getConnection(); list.addLast(connection);

        Connection conn = list.removeFirst();
        return conn;
    
/**
* 返回到连接池子中 */
    public static void addBack(Connection conn)
        if (list.size() >= 10) 
            try 
                conn.close();
             catch (SQLException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        else
            list.addLast(conn);  //10
 
/**
* 获取连接池子中连接数量的方法 */
    public static int getSize()
        return list.size();
 

java规范实现连接池

Java为连接池实现提供了一个规范(接口),规范的写法,我们需要实现DataSource接口! 但是实现DataSource接口有一个弊端,没有提供回收链接方法!这里我们将使用装饰者模式装饰Connection。

具体实现代码如下:

public class MyConnection   implements Connection
//将被装饰者导入
private Connection conn;
private LinkedList<Connection> list;
    public MyConnection(Connection conn, LinkedList<Connection> list) 
        super();
        this.conn = conn;
        this.list = list;
    
    
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException 
        return conn.unwrap(iface);
    
    
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException 
        return conn.isWrapperFor(iface);
    
    
    @Override
    public Statement createStatement() throws SQLException 
        return conn.createStatement();
    
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException 
        return conn.prepareStatement(sql);
    
    
    @Override
    public CallableStatement prepareCall(String sql) throws SQLException 
        return null;
    
    
    @Override
    public String nativeSQL(String sql) throws SQLException 
        return null;
    
    
    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException 
    
    
    @Override
    public boolean getAutoCommit() throws SQLException 
        return false;
    
    
    @Override
     public void commit() throws SQLException 
        conn.commit();
	
	
    @Override
    public void rollback() throws SQLException 
        conn.rollback();
    
    
    @Override
    public void close() throws SQLException 
        list.addLast(conn);

... 

不同连接池的相关参数:

参数参数含义DBCPc3p0Druid
最小连接数是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。mindle(0)minPoolSize()mindle()
最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。maxTotal(0)maxPoolSize()maxActive(8)
初始化连接数连接池启动时创建的初始化数据库连接数量initialSize(0)initialPoolSize()initialSize(0)
最大等待时间当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负 数使得无限等待(根据不同连接池配置)maxWaitMilis(毫秒)maxldle Time(0秒)maxWait(毫秒)
  • 注1 在DBCP连接池的配置中,还有一个maxIdle的属性,表示最大空闲连接数,超过的空闲连接将被释 放,默认值为8。对应的该属性在Druid连接池已不再使用,配置了也没有效果,c3p0连接池则没有对 应的属性。
  • 注2 数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连 接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个 连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到 maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在 连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

DBCP连接池

DBCP是一个依赖Jakartacommons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的就是DBCP。

DBCP连接池的使用

  1. 导入相应jar包
    mysql-jdbc.jar
    commons-dbcp.jar
    commons-pool.jar
  2. 硬编码使用DBCP

所谓的硬编码方式就是在代码中添加配置

@Test
public void testHard() throws SQLException
// 硬编码 使用DBCP连接池子
	BasicDataSource source = new BasicDataSource(); //设置连接的信息
	source.setDriverClassName("com.mysql.jdbc.Driver"); 
	source.setUrl("jdbc:mysql://localhost:3306/day2"); 			
	source.setUsername("root"); source.setPassword("111");
	Connection connection = source.getConnection();
 	String sql = "select * from student";
    Statement createStatement = connection.createStatement();
    ResultSet executeQuery = createStatement.executeQuery(sql);
    while (executeQuery.next()) 
        System.out.println(executeQuery.getString(2));
    
	connection.close(); //回收 
  1. 软编码使用DBCP

所谓的软编码,就是在项目中添加配置文件,这样就不需要每次代码中添加配合

  • 项目中添加配置 文件名称: info.properties 文件位置: src下
#连接设置
	driverClassName=com.mysql.jdbc.Driver 
	url=jdbc:mysql://localhost:3306/day2
	username=root
	password=111
	#<!-- 初始化连接 -->
	initialSize=10
	#最大连接数量
	maxActive=50
	#<!-- 最大空闲连接 -->
	maxIdle=20
	#<!-- 最小空闲连接 -->
	minIdle=5
	#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60-->
	maxWait=6000
  • DButils工具类 代码实现
//1.创建dbcp的工具类对象
static BasicDataSource datasource=new BasicDataSource(); //2.加载驱动
	static 
	try  //加载属性文件
	//1.使用工具类 ,参数是属性文件的文件名(不要加后缀) 
		ResourceBundle bundle = ResourceBundle.getBundle("db"); 
		driverClass = bundle.getString("driverclass");
		url = bundle.getString("url");
		username = bundle.getString("uname");
		password = bundle.getString("upass"); 
		init=bundle.getString("initsize");
	
		//2.将驱动地址等信息传递给dbcp 
		datasource.setDriverClassName(driverClass); 	
		datasource.setUrl(url);
		datasource.setUsername(username);
	    datasource.setPassword(password);
	    datasource.setInitialSize(Integer.parseInt(init));
     catch (Exception e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
 
//3.获得连接
public static Connection getConn() 
    try 
        con= datasource.getConnection();
     catch (SQLException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
	
	return con; 

Druid(德鲁伊)连接池

阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个 ProxyDriver(代理驱动),一系列内置的JDBC组件库,一个SQL Parser(sql解析器)。支持所有JDBC兼 容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。

Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。

Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。

简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防
御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

Druid 是目前比较流行的高性能的,分布式列存储的OLAP框架(具体来说是MOLAP)。它有如下几个特点:

  1. . 亚秒级查询
    druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理 想方式。
  2. 实时数据注入 druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性
  3. 可扩展的PB级存储
    druid集群可以很方便的扩容到PB的数据量,每秒百 万级别的数据注入。即便在加大数据规模的情况下,也能保证时其效性
  4. 多环境部署
    druid既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括 hadoop,spark,kafka,storm和samza等
  5. 丰富的社区
    druid拥有丰富的社区,供大家学习

使用步骤

  1. 导入jar包
  2. 编写工具类
/**
* 阿里的数据库连接池 * 性能最好的
* Druid
* */
public class DruidUtils  //声明连接池对象
    private static DruidDataSource ds;
    static
		///实例化数据库连接池对象
		ds=new DruidDataSource(); //实例化配置对象
		Properties properties=new Properties(); 
		try 
			//加载配置文件内容
			properties.load(DruidUtils.class.getResourceAsStream("dbcpconfig.properties")); //设置驱动类全称
			ds.setDriverClassName(properties.getProperty("driverClassName")); //设置连接的数据库
			ds以上是关于JAVA基础:JDBC的使用 附详细代码的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio使用JDBC远程连接mysql的注意事项(附示例)

使用JDBC技术连接数据库(附源码)--JAVA的简单应用

零基础python之4函数重用-函数与模块(附详细的步骤和程序)

Web前端:HTML最强总结 附详细代码

MySQL——基础知识总结超详细版本做一个简易的图书馆系系统附源代码

Web前端:CSS最强总结 附详细代码