jdbc操作管理事务----用户转账操作

本文详细介绍了Java中使用JDBC进行事务管理的原理和步骤,包括事务的ACID特性以及如何通过Druid数据源来管理数据库连接和事务。示例代码展示了如何在DruidJdbcUtils工具类中实现事务的开启、提交和回滚,并在实际的转账操作中应用这些概念。此外,还提供了Druid数据源的配置和连接池管理的相关代码。
摘要由CSDN通过智能技术生成

一、事务

种机制,某个业务中多次调用dao完成多个sql同时执行,要么同时执行成功/要么同时执行失败
否则,就出现数据紊乱! 使用事务管理(JDBC方式操作)

 二、需求

用户发送请求,通过连接池获取Connection对象
      Connection:管理事务的功能

      void setAutoCommit(boolean autoCommit) throws SQLException

      默认情况下,新创建的连接对象处于自动提交模式 参数为true,声明为false,禁用自动提交,需要收到提交sql

        void rollback() throws SQLException:当前执行提交之前,如果sql发生异常,将撤销之前的所有操作

         void commit() SQLException:如果执行过程中没有问题或者回滚了,都提交事务,将之前的所有操作永久保存!

 三、步骤:

1、properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb_01?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000

2、 DruidJdbcUtils工具

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @author Kuke
 * @date 2021/8/18
 * 工具类---->DataSource----->获取数据库的连接对象 Connection以及后期管理事务
 *
 * 获取连接对象----静态方法
 * 关闭资源-----静态方法
 */
public class DruidJdbcUtils {

    //成员变量位置
    private  static DataSource ds ;
    //为了保证线程安全:每一线程使用自己的Connection (张三/李四)
    private static ThreadLocal<Connection>  t1 = new ThreadLocal<>() ; //提供线程的局部变量保存连接对象



    //构造方法私有化
    private DruidJdbcUtils(){}

    //静态代码块
    static{
        try {
            //读取数据库连接池的配置文件----->通过DruidDataSourceFactory工厂类创建DataSource
            //创建一个属性集合列表
            Properties prop = new Properties() ;
            //读取druid.properties
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");

            //将资源文件所在的输入流加载列表中
            prop.load(inputStream);
            ds = DruidDataSourceFactory.createDataSource(prop); //底层子实现类:DruidDataSource
            //System.out.println("数据源获取成功");

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //提供静态方法:单独获取数据源
    public static DataSource getDataSource(){
        return ds ;
    }


    //获取连接对象Connection静态功能

    public static Connection getConnection(){
        //从ThreadLocal中获取局部变量的副本:Connection
        /**
         *   public T get()  :从线程中获取局部变量的副本!
         */
        Connection conn =  null ;
        try {
            conn  =  t1.get();
            if(conn==null){
                //如果空,需要从数据库的连接池中获取连接对象
                 conn  = ds.getConnection();
                //获取到之后,每一线程执行自己的Connection
                //将获取到的连接对象 绑定到当前线程中
                t1.set(conn);
            }
            //如果不为空,说明ThreadLocal线程中已经存在Connection
            return conn ; //
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null ;

    }

    //关闭(释放资源)资源
    public static void close(ResultSet rs, Statement stmt,Connection conn)  {
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
                //关闭之后,归还到连接池中,需要从当前线程中解绑
                t1.remove();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close( Statement stmt,Connection conn)  {
        close(null,stmt,conn);
    }

    //事务管理代码 --- 加入

    //定义开启事务的方法
    //定义回滚的方法
    public static void rollback() throws SQLException {
        Connection connection = DruidJdbcUtils.getConnection();
        //调用回滚方法
        connection.rollback();
        //使用完毕,归还连接池中
        connection.close();
        //从当前线程中解绑
        t1.remove();

    }
    //定义提交的方法---->需要将当前线程中绑定的Connetion remove掉

    public static void main(String[] args) {
       // DataSource ds = DruidJdbcUtils.getDataSource();
        //System.out.println(ds);


        Connection connection = DruidJdbcUtils.getConnection();
        System.out.println(connection);
    }
}

3、实现类

public class JdbcTransactionDemo {
    public static void main(String[] args)  {
        Connection connection = null;
        PreparedStatement stmt1 = null;
        PreparedStatement stmt2 = null;

        try {
            //通过DruidJdbcUtils获取连接对象
            connection = DruidJdbcUtils.getConnection();
            //开启事务---将自动提交禁用调用,参数为false,手动提交
            connection.setAutoCommit(false);

            //准备sql语句
            String sql1 = "update account set balance = balance - ? where id  = ?" ;
            //创建预编译对象对sql1进行预编译
            stmt1 = connection.prepareStatement(sql1);
            //参数赋值
            stmt1.setInt(1,500);
            stmt1.setInt(2,1);
            //执行更新
            stmt1.executeUpdate() ;

            //程序出问题了
//            int i = 10 /0 ;

            String sql2 = "update account set balance = balance + ? where id = ? " ;
            //创建预编译对象对sql2进行预编译
            stmt2 = connection.prepareStatement(sql2);
            //参数赋值
            stmt2.setInt(1,500);
            stmt2.setInt(2,2);
            //执行更新
            stmt2.executeUpdate() ;

            //如果没有问题,正常提交
            connection.commit();
            System.out.println("转账成功...");
        } catch (SQLException e) {

            //处理异常: 直接事务回滚
            //有异常,执行catch语句,就回滚
            try {
                System.out.println("程序出问题了...");
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            //e.printStackTrace();
        }


        //释放资源
       DruidJdbcUtils.close(stmt1,connection);
       DruidJdbcUtils.close(stmt2,connection);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彦登的登

动力来源

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值