【WEEK8】 【DAY1】【DAY2】JDBC—事务数据库连接池【中文版】

2024-04-16 15:12

本文主要是介绍【WEEK8】 【DAY1】【DAY2】JDBC—事务数据库连接池【中文版】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接上文【WEEK7】 【DAY5】JDBC—PreparedStatement对象【中文版】

目录

  • 2024.4.15 Monday
  • 10.5.事务
    • 10.5.1.要么都成功,要么都失败
    • 10.5.2.ACID原则(详见6.2.事务的ACID原则)
    • 10.5.3.实例
      • 10.5.3.1.成功的
      • 10.5.3.2.失败的
      • 10.5.3.3.步骤总结
  • 10.6.数据库连接池
    • 10.6.1.“数据库连接——执行完毕——释放”这个“连接+释放”的过程十分浪费资源
    • 10.6.2.池化技术:预先准备一些资源,需要使用资源时就可以直接使用预先准备好的
    • 10.6.3.编写连接池只需要实现一个接口:DataSource
    • 10.6.4.开源数据源实现
    • 10.6.5.DBCP
      • 10.6.5.1.需要用到的jar包
      • 10.6.5.2.新建dbcpconfig.properties文件
      • 10.6.5.3.新建utils文件
  • 2024.4.16 Tuesday
      • 10.6.5.4.新建TestDBCP文件
    • 10.6.6.C3P0
      • 10.6.6.1.需要用到的jar包
      • 10.6.6.2.新建c3p0-config.xml文件
      • 10.6.6.3.新建utils文件
      • 10.6.6.4.新建TestC3P0文件
      • 10.6.6.5.结论:无论使用什么数据源,本质相同,DataSource接口不会变,方法就不会变
    • 10.6.7.下载jar包网址备份

2024.4.15 Monday

10.5.事务

10.5.1.要么都成功,要么都失败

10.5.2.ACID原则(详见6.2.事务的ACID原则)

10.5.2.1.原子性:要么全部完成,要么都不完成
10.5.2.2.一致性:总数不变
10.5.2.3.隔离性:多个进程互不干扰
10.5.2.4.持久性:一旦提交不可逆,持久化到数据库
10.5.2.5.隔离性的问题:

  • 脏读:一个事物读取了另一个没有提交的事物
  • 不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
  • 虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致

10.5.3.实例

10.5.3.1.成功的

package lesson.four;import lesson.two.utils.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class TestTransaction1 {public static void main(String[] args) {Connection conn = null;PreparedStatement st = null;ResultSet rs = null;try {conn = JdbcUtils.getConnection();//关闭数据库的自动提交功能,此时会自动开启事务。即:关闭自动提交=开启事务conn.setAutoCommit(false);String sql1 = "UPDATE account SET money = money - 100 WHERE `NAME` = 'A'";st = conn.prepareStatement(sql1);st.executeUpdate();String sql2 = "UPDATE account SET money = money + 100 WHERE `NAME` = 'B'";st = conn.prepareStatement(sql2);st.executeUpdate();//业务完毕,提交事务conn.commit();;System.out.println("成功");} catch (SQLException e) {try {conn.rollback();} catch (SQLException ex) {throw new RuntimeException(ex);}throw new RuntimeException(e);} finally {{JdbcUtils.release(conn,st,rs);}}}
}
  • 结果
    在这里插入图片描述
    在这里插入图片描述->在这里插入图片描述

10.5.3.2.失败的

package lesson.four;import lesson.two.utils.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class TestTransaction2 {public static void main(String[] args) {Connection conn = null;PreparedStatement st = null;ResultSet rs = null;try {conn = JdbcUtils.getConnection();//关闭数据库的自动提交功能,此时会自动开启事务。即:关闭自动提交=开启事务conn.setAutoCommit(false);String sql1 = "UPDATE account SET money = money - 100 WHERE `NAME` = 'A'";st = conn.prepareStatement(sql1);st.executeUpdate();int x = 1/0;    //一定会出现异常(为了使该事务不能完全执行成功写的错误行)用于测试回滚String sql2 = "UPDATE account SET money = money + 100 WHERE `NAME` = 'B'";st = conn.prepareStatement(sql2);st.executeUpdate();//业务完毕,提交事务conn.commit();;System.out.println("成功");} catch (SQLException e) {try {conn.rollback();    //如果失败则默认回滚事务(这行不一定要写)} catch (SQLException ex) {throw new RuntimeException(ex);}throw new RuntimeException(e);} finally {{JdbcUtils.release(conn,st,rs);}}}
}
  • 结果
    在这里插入图片描述

执行conn.rollback(); //如果失败则默认回滚事务(这行不一定要写)
即使sql1对应的语句部分修改曾经执行成功过,但是由于回滚导致表中的最终结果不变
在这里插入图片描述

10.5.3.3.步骤总结

  • 开启事务conn.setAutoCommit(false);
  • 一组业务执行完毕,提交事务
  • 可以在catch语句中显示地定义‘回滚语句’,但即使不写,默认情况就会回滚

10.6.数据库连接池

10.6.1.“数据库连接——执行完毕——释放”这个“连接+释放”的过程十分浪费资源

10.6.2.池化技术:预先准备一些资源,需要使用资源时就可以直接使用预先准备好的

10.6.2.1.相当于:“开门——业务员:等待——服务”
10.6.2.2.最小连接数 根据 常用连接数 决定。e.g.常用10个连接->最小连接数是10
10.6.2.3.最大连接数:业务最高承载上限。e.g.承载上限是15则最大连接数是15。超出部分需要排队等待,如果排队等待的时间超过某个阈值(如:100ms’),则称为 超时等待

10.6.3.编写连接池只需要实现一个接口:DataSource

10.6.4.开源数据源实现

10.6.4.1.DBCP(DataBase connection pool)
10.6.4.2.C3P0
10.6.4.3.Druid:阿里巴巴的
10.6.4.4.使用了这些数据库连接池之后,个人在项目开发中就不需要编写连接数据库的代码了

10.6.5.DBCP

10.6.5.1.需要用到的jar包

下载地址都是官网,可参考这篇博客,导入方式和connector相同:https://blog.csdn.net/qq_45523411/article/details/121517140
在进行到新TestDBCP文件运行时发现报错:问题是2.0以上版本的dbcp需要再导入logging包,教程(内附有下载链接)如下:https://blog.csdn.net/qq_41115379/article/details/108947898
在这里插入图片描述
在这里插入图片描述

10.6.5.2.新建dbcpconfig.properties文件

在这里插入图片描述

#连接设置:这里的名字是DBCP数据源中定义好的
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/p37jdbc?useUnicode=true & characterEncoding=utf8 & useSSL=true
username = root
password = 123456#以下所有内容都可以不手动设置
#<!-- 初始化连接 -->
initialSize=10#最大连接数量
maxActive=50#<!-- 最大空闲连接 -->
maxIdle=20#<!-- 最小空闲连接 -->
minIdle=5#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
maxWait=60000#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED

10.6.5.3.新建utils文件

和JdbcUtils几乎一样,仅更换了输入流的来源
在这里插入图片描述

package lesson.five.utils;import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JdbcUtils_DBCP {private static  DataSource dataSource = null;static {try{//获得类加载器.获取资源,获取的资源的名字:是src文件夹下的文件名,会返回一个输入流InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");//把流读到properties类里Properties properties = new Properties();properties.load(in);//创建数据源 工厂模式(用于创建对象)//点开BasicDataSourceFactory查看可见封装完毕的各种类,和lesson.two.utils中相比,个人所需书写的代码量减少了dataSource = BasicDataSourceFactory.createDataSource(properties);} catch (Exception e) {throw new RuntimeException(e);  //这是默认生成的
//            e.printStackTrace();  //这两行任选一行亦可}}//获取连接public static Connection getConnection() throws SQLException {return dataSource.getConnection();  //只需要在这里修改直接(从数据源中)获取连接即可}// 释放连接资源public static void release(Connection conn, Statement st, ResultSet rs){if(rs != null){try {rs.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(st != null){try {st.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(conn != null){try {conn.close();} catch (SQLException e) {throw new RuntimeException(e);}}}}

2024.4.16 Tuesday

10.6.5.4.新建TestDBCP文件

参考lesson.TestInsert,只修改部分的代码

package lesson.five;import lesson.five.utils.JdbcUtils_DBCP;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class TestDBCP {public static void main(String[] args) {Connection conn = null;PreparedStatement st = null;try {//本质是更换了数据源(在获取连接和关闭连接时代码有所区别),和lesson.three的TestInsert其他部分没有任何区别conn = JdbcUtils_DBCP.getConnection();//和一般的statement区别:使作为用问号作为占位符String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?,?)";st = conn.prepareStatement(sql);   //预编译SQL:先生成SQL但不执行//手动给参数赋值st.setInt(1,4); //idst.setString(2,"lqf");st.setString(3,"987654");st.setString(4,"27046873@qq.com");st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));//执行int i = st.executeUpdate();if(i > 0){System.out.println("插入成功");}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils_DBCP.release(conn,st,null);}}
  • 结果
    在这里插入图片描述
    在这里插入图片描述

10.6.6.C3P0

10.6.6.1.需要用到的jar包

参考教程:
打开压缩包后注意使用的jar包的名称不含有source,是lib文件夹下的文件
https://blog.csdn.net/YyjYsj/article/details/108854804
在这里插入图片描述

10.6.6.2.新建c3p0-config.xml文件

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config><!--
c3p0的缺省(默认)配置
如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认)-->
<default-config><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/p37jdbc?useUnicode=true &amp; characterEncoding=utf8 &amp; useSSL=true &amp; serverTimezone=UTC</property><property name="user">root</property><property name="password">123456</property><property name="acquiredIncrement">5</property><property name="initialPoolSize">10</property><property name="minPoolSize">5</property><property name="maxPoolSize">20</property>
</default-config><!--
c3p0的命名配置
如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");"这样写就表示使用的是name是mysql
&ndash;&gt;
--><named-config name="MySQL"><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/p37jdbc?useUnicode=true &amp; characterEncoding=utf8 &amp; useSSL=true</property><property name="user">root</property><property name="password">123456</property><property name="acquiredIncrement">5</property><property name="initialPoolSize">10</property><property name="minPoolSize">5</property><property name="maxPoolSize">20</property></named-config></c3p0-config>
<!--        这里人话说就是可以创建多个不同的数据库连接池~~-->

10.6.6.3.新建utils文件

在这里插入图片描述

package lesson.five.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;public class JdbcUtils_C3P0 {private static  ComboPooledDataSource dataSource = null;static {try {//代码版配置(但是一般不使用)
//            dataSource = new ComboPooledDataSource();
//            dataSource.setDriverClass();
//            dataSource.setUser();
//            dataSource.setPassword();
//            dataSource.setJdbcUrl();
//
//            dataSource.setMaxPoolSize();
//            dataSource.setMinPoolSize();//创建数据源 工厂模式(用于创建对象)dataSource = new ComboPooledDataSource("MySQL");   //配置文件写法。也可在()内添加已完成的“命名配置”} catch (Exception e) {throw new RuntimeException(e);  //这是默认生成的
//            e.printStackTrace();  //这两行任选一行亦可}}//获取连接public static Connection getConnection() throws SQLException {return dataSource.getConnection();  //只需要在这里修改直接(从数据源中)获取连接即可}// 释放连接资源public static void release(Connection conn, Statement st, ResultSet rs){if(rs != null){try {rs.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(st != null){try {st.close();} catch (SQLException e) {throw new RuntimeException(e);}}if(conn != null){try {conn.close();} catch (SQLException e) {throw new RuntimeException(e);}}}}

10.6.6.4.新建TestC3P0文件

package lesson.five;import lesson.five.utils.JdbcUtils_C3P0;
import lesson.five.utils.JdbcUtils_DBCP;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class TestC3P0 {public static void main(String[] args) {Connection conn = null;PreparedStatement st = null;try {//本质是更换了数据源(在获取连接和关闭连接时代码有所区别),和lesson.three的TestInsert其他部分没有任何区别conn = JdbcUtils_C3P0.getConnection();  //和lesson.five.TestDBCP相比的区别就是修改了这(使用外部包)//和一般的statement区别:使作为用问号作为占位符String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?,?)";st = conn.prepareStatement(sql);   //预编译SQL:先生成SQL但不执行//手动给参数赋值//set...的语法对应了传入函数参数每个位置以及希望设置成的参数st.setInt(1,5); //idst.setString(2,"wlj");st.setString(3,"456789");st.setString(4,"27046873@qq.com");st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));//new Date().getTime()即:外层括号内是计算机的时间,需要转化成mysql的时间//sql.Date是数据库时间,util.Date是Java的//因为setDate的源码中时间的参数是数据库类型的:void setDate(int parameterIndex, java.sql.Date x)//所以要另外用new Date().getTime()获得时间戳(这个版本里需要使用“new java.util.Date().getTime()”才不报错)//执行int i = st.executeUpdate();if(i > 0){System.out.println("插入成功");}} catch (SQLException e) {e.printStackTrace();} finally {JdbcUtils_C3P0.release(conn,st,null);}}
}
  • 结果
    在这里插入图片描述
    在这里插入图片描述

10.6.6.5.结论:无论使用什么数据源,本质相同,DataSource接口不会变,方法就不会变

10.6.7.下载jar包网址备份

https://mvnrepository.com/

这篇关于【WEEK8】 【DAY1】【DAY2】JDBC—事务数据库连接池【中文版】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/909144

相关文章

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

postgresql数据库基本操作及命令详解

《postgresql数据库基本操作及命令详解》本文介绍了PostgreSQL数据库的基础操作,包括连接、创建、查看数据库,表的增删改查、索引管理、备份恢复及退出命令,适用于数据库管理和开发实践,感兴... 目录1. 连接 PostgreSQL 数据库2. 创建数据库3. 查看当前数据库4. 查看所有数据库

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指