• Day24-事务和数据库连接池


    Day24

    事务

    要么都成功,要么都失败

    ACID原则

    • 原子性:要么全部成功,要么全部失败

    • 一致性:总数不变

    • 隔离性:多个进程互不干扰

    • 持久性:一旦提交不可逆,持久化到数据库了

    隔离性的问题:

    • 脏读:一个事务读取了另外一个没有提交的事务

    • 不可重复读:在同一个事务内,重复读取表中数据,表数据发生了改变

    • 幻读:在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致

    案例

    前提:

    在这里插入图片描述

    成功提交

    package com.ghy.lesson04;
    import com.ghy.lesson02.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 pst=null;
            ResultSet rs=null;
            try {
                conn = JdbcUtils.getConnection();
                //关闭数据库自动提交后,会自动开启事务
                conn.setAutoCommit(false);
                //sql
                String sql1="UPDATE account SET money = money-100 WHERE NAME ='A'";
                pst = conn.prepareStatement(sql1);
                pst.executeUpdate();
    
                String sql2="UPDATE account SET money = money+100 WHERE NAME ='B'";
                pst = conn.prepareStatement(sql2);
                pst.executeUpdate();
    
                //业务完毕,提交事务
                conn.commit();
                System.out.println("事务提交成功!");
            } catch (SQLException e1) {
                try {
                    conn.rollback();//如果失败,则回滚事务.不写这条也会默认回滚。
                } catch (SQLException e2) {
                    e2.printStackTrace();
                }
                e1.printStackTrace();
            }finally {
                JdbcUtils.release(conn,pst,rs);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    输出

    在这里插入图片描述

    查看

    在这里插入图片描述

    提交失败

    package com.ghy.lesson04;
    import com.ghy.lesson02.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 pst=null;
            ResultSet rs=null;
            try {
                conn = JdbcUtils.getConnection();
                //关闭数据库自动提交后,会自动开启事务
                conn.setAutoCommit(false);
                //sql
                String sql1="UPDATE account SET money = money-100 WHERE NAME ='A'";
                pst = conn.prepareStatement(sql1);
                pst.executeUpdate();
    
                int x=1/0;//报错
    
                String sql2="UPDATE account SET money = money+100 WHERE NAME ='B'";
                pst = conn.prepareStatement(sql2);
                pst.executeUpdate();
    
                //业务完毕,提交事务
                conn.commit();
                System.out.println("事务提交成功!");
            } catch (SQLException e1) {
                try {
                    conn.rollback();//如果失败,则回滚事务.不写这条也会默认回滚。
                } catch (SQLException e2) {
                    e2.printStackTrace();
                }
                e1.printStackTrace();
            }finally {
                JdbcUtils.release(conn,pst,rs);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    输出

    在这里插入图片描述

    数据库连接池

    数据库连接》执行完毕》释放

    下一个再继续连接》释放,这样就十分浪费资源

    池化技术:准备一些预先的资源,过来就连接预先准备好的

    常用连接数:10

    最小连接数:10

    最大连接数:15(业务最高承载上限)

    排队等待(超过最大连接数之后)

    等待超时:100ms(超过某个时间自动断掉)

    实现:

    编写连接池,实现一个接口(DataSource)

    开源数据源实现(拿来即用)

    DBCP

    C3P0

    Druid(阿里巴巴)

    使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码

    DBCP

    需要的jar包

    commons-dbcp-1.4

    commons-pool-1.6

    • 配置文件dbcpconfig.properties
    #连接设置 这里的名字,是DBCP数据源中定义好的
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
    username=root
    password=123456
    
    #初始化连接
    initialSize=10
    
    #最大连接数量
    maxActive=50
    
    #最大空闲连接
    maxIdle=20
    
    #最小空闲连接
    minIdle=5
    
    #超时等待时间以毫秒为单位 6000毫秒/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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 工具类
    package com.ghy.lesson05.utils;
    import org.apache.commons.dbcp.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{
                //读取配置文件
                InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
                Properties pro=new Properties();
                pro.load(in);
    
                //创建数据源   工厂模式-->创建
                dataSource =BasicDataSourceFactory.createDataSource(pro);
    
            } catch (Exception 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){
                    e.printStackTrace();
                }
            }
    
            if(st!=null){
                try{
                    st.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try{
                    conn.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 测试
    package com.ghy.lesson05;
    import com.ghy.lesson02.utils.JdbcUtils;
    import com.ghy.lesson05.utils.JdbcUtils_DBCP;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestDBCP {
        public static void main(String[] args) {
            Connection conn=null;
            PreparedStatement pst=null;
            ResultSet rs=null;
    
            try {
                conn = JdbcUtils_DBCP.getConnection();
    
                //区别
                //可以使用问号代替参数
                String sql="INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
    
                pst = conn.prepareStatement(sql);//预编译,先写SQL然后不执行
    
                // 手动给参数赋值
                pst.setInt(1,6);
                pst.setString(2,"中赵");
                pst.setString(3,"123456");
                pst.setString(4,"zhongzhao@qq.com");
                //注意点:sql.Date   数据库  最后通过java.sql.Date转换
                //util.Date   Java   new Date().getTime()获得时间戳
                pst.setDate(5,new java.sql.Date(new java.util.Date().getTime()));
    
                //执行SQL
                int i=pst.executeUpdate();//没有传参
                if(i>0){
                    System.out.println("插入成功!!!");
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                JdbcUtils.release(conn,pst,rs);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    输出

    在这里插入图片描述

    插入前

    在这里插入图片描述

    插入后

    在这里插入图片描述

    C3P0

    需要的jar包

    [c3p0-0.9.5.5.jar和mchange-commons-java-0.2.19.jar下载](c3p0-0.9.5.5.jar下载及Maven、Gradle引入代码,pom文件及包内class -时代Java (nowjava.com))

    • 配置文件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.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&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
        -->
        <name-config name="MySQL">
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&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>
        </name-config>
    </c3p0-config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 工具类
    package com.ghy.lesson05.utils;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    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) {
                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){
                    e.printStackTrace();
                }
            }
    
            if(st!=null){
                try{
                    st.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try{
                    conn.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 测试类
    package com.ghy.lesson05;
    import com.ghy.lesson02.utils.JdbcUtils;
    import com.ghy.lesson05.utils.JdbcUtils_C3P0;
    import com.ghy.lesson05.utils.JdbcUtils_DBCP;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestC3P0 {
        public static void main(String[] args) {
            Connection conn=null;
            PreparedStatement pst=null;
            ResultSet rs=null;
    
            try {
                conn = JdbcUtils_C3P0.getConnection();//原来是自己实现的,现在用的是别人的
    
                //区别
                //可以使用问号代替参数
                String sql="INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES(?,?,?,?,?)";
    
                pst = conn.prepareStatement(sql);//预编译,先写SQL然后不执行
    
                // 手动给参数赋值
                pst.setInt(1,7);
                pst.setString(2,"大赵");
                pst.setString(3,"123456");
                pst.setString(4,"dazhao@qq.com");
                //注意点:sql.Date   数据库  最后通过java.sql.Date转换
                //util.Date   Java   new Date().getTime()获得时间戳
                pst.setDate(5,new java.sql.Date(new java.util.Date().getTime()));
    
                //执行SQL
                int i=pst.executeUpdate();//没有传参
                if(i>0){
                    System.out.println("插入成功!!!");
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {
                JdbcUtils.release(conn,pst,rs);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    输出

    在这里插入图片描述

    查看

    插入前

    在这里插入图片描述

    插入后

    在这里插入图片描述

    总结

    无论用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变

  • 相关阅读:
    400 页共计 800 道软件测试面试真题汇总,2023年吐血整理
    python学习004——zip()函数
    【MATLAB源码-第47期】基于matlab的GMSK调制解调仿真,输出误码率曲线,采用相干解调。
    mysql入门笔记
    电容笔可以用什么代替?双十二平价电容笔推荐
    JavaSE——字符串常量池(StringTable)
    OSI协议
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java学生信息管理系统ow05a
    Ubuntu下解压文件(提取文件总是报错)文件是zip 格式
    UE4 动画资源曲线导出以及导入
  • 原文地址:https://blog.csdn.net/GHY0911/article/details/126185576