本文主要是介绍【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 & characterEncoding=utf8 & useSSL=true & 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
–>
--><named-config name="MySQL"><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/p37jdbc?useUnicode=true & characterEncoding=utf8 & 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—事务数据库连接池【中文版】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!