【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

相关文章

数据库面试必备之MySQL中的乐观锁与悲观锁

《数据库面试必备之MySQL中的乐观锁与悲观锁》:本文主要介绍数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数... 目录一、引言二、乐观锁(一)原理(二)应用场景(三)示例代码三、悲观锁(一)原理(二)应用场景(三)示例

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优