【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分区技术通过将大表分割成多个较小片段,提高查询性能、管理效率和数据存储效率,本文就来介绍一下mysql数据库分区的使用,感兴趣的可以了解一下... 目录【一】分区的基本概念【1】物理存储与逻辑分割【2】查询性能提升【3】数据管理与维护【4】扩展性与并行处理【二】分区的

IDEA如何切换数据库版本mysql5或mysql8

《IDEA如何切换数据库版本mysql5或mysql8》本文介绍了如何将IntelliJIDEA从MySQL5切换到MySQL8的详细步骤,包括下载MySQL8、安装、配置、停止旧服务、启动新服务以及... 目录问题描述解决方案第一步第二步第三步第四步第五步总结问题描述最近想开发一个新应用,想使用mysq

Oracle数据库使用 listagg去重删除重复数据的方法汇总

《Oracle数据库使用listagg去重删除重复数据的方法汇总》文章介绍了在Oracle数据库中使用LISTAGG和XMLAGG函数进行字符串聚合并去重的方法,包括去重聚合、使用XML解析和CLO... 目录案例表第一种:使用wm_concat() + distinct去重聚合第二种:使用listagg,

Java读取InfluxDB数据库的方法详解

《Java读取InfluxDB数据库的方法详解》本文介绍基于Java语言,读取InfluxDB数据库的方法,包括读取InfluxDB的所有数据库,以及指定数据库中的measurement、field、... 首先,创建一个Java项目,用于撰写代码。接下来,配置所需要的依赖;这里我们就选择可用于与Infl

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

SQL Server数据库磁盘满了的解决办法

《SQLServer数据库磁盘满了的解决办法》系统再正常运行,我还在操作中,突然发现接口报错,后续所有接口都报错了,一查日志发现说是数据库磁盘满了,所以本文记录了SQLServer数据库磁盘满了的解... 目录问题解决方法删除数据库日志设置数据库日志大小问题今http://www.chinasem.cn天发