JDBC学习笔记第九篇

2023-12-29 09:13:27
解决druid的线程同步机制,想同步curd的时候不用再传入connection连接,让它们得到相同的连接
package com.shayiheng.api.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.shayiheng.api.druid.DruidUsePart;

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

/**
 * @Author Tom
 * @Date 2023/12/22 21:42
 * @Description:
 *
 * v1.0版本工具类
 *  内部包含一个连接池对象,并且对外提供获取连接和回收连接的方法!
 *  小建议:
 *      工具类的方法,推荐写成静态的,外部调用会更加方便
 *  实现:
 *      属性 连接池对象[实例化一次]
 *          单例模式
 *          static{
 *              全局实例话调用一次
 *          }
 *      方法
 *          对外提供连接的方法
 *          回收外部传入连接的方法
 *
 * TODO:
 *     利用线程本地变量,存储连接信息!确保一个线程的多个方法可以获取同一个connection!
 *     优势:事物操作的时候 service 和 dao 属于同一个线程,不用再传递参数了
 *     可调用getConnection获取相同的连接
 *
 */
public class JdbcUtilsV2 {
    private static DataSource dataSource=null;//连接池对象
    private static  ThreadLocal<Connection> t1=new ThreadLocal<>();
    static {
        //初始化静态代码块
        Properties properties=new Properties();
        InputStream ips = DruidUsePart.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(ips);
        }catch (IOException e){
            throw  new RuntimeException(e);
        }
        try {
            dataSource= DruidDataSourceFactory.createDataSource(properties);
        }catch (Exception e){
            throw  new RuntimeException(e);
        }
    }

    /**
     * 对外提供连接的方法
     * @return
     */
    public static Connection getConnection() throws SQLException {

        //线程是否存在
        Connection connection=t1.get();

        //压根没有创建
        if (connection==null){
            //获取连接
            connection=dataSource.getConnection();
            //往线程本地变量里存一份
            t1.set(connection);
        }
        return connection;
    }

    public static void freeConnection() throws SQLException {
        Connection connection=t1.get();
        if (connection!=null) {
            //情况线程本地变量
            t1.remove();
            connection.setAutoCommit(true);//回到默认
            connection.close();//连接池的连接,调用close就是回收!
        }
    }
}
package transactionnew;

/**
 * @Author Tom
 * @Date 2023/12/22 13:44
 * @Description: bank表的数据库操作方法存储类
 *
 * 事物的特性
 * 1.原子性(Atomicity):指事物是一个不可分割的工作单位,事物中的操作要么都发生,要么一个都不发生
 * 2.一致性(Consistency):事物必须使数据库从一个一直性变换到另一个一直性状态
 * 3.隔离性(Isolation):事物的隔离性是指一个事物的执行不能被其他事物干扰
 * 4.持久性(Durability):持久性是指一个事物一旦被提交,它对数据库中的数据的改变是永久性的
 *
 * 事物的类型
 * 自动提交:每条语句自动存储一个事物中,执行成功自动提交,执行失败自动会滚。
 * 手动提交:手动开启事物,添加语句,手动提交或者手动会滚即可!
 *
 *
 * Sql开启事务的方式
 * 	针对自动提交:关闭自动提交即可,多条语句添加以后,最终手动提交或者回滚!(推荐)
 * 	SET autocommit= off; //关闭当前连接自动事物提交方式
 * 	# 只有当前连接有效
 * 	# 编写SQL语句即可
 * 	SQL
 * 	SQL
 * 	SQL
 * 	#手动提交或者会滚[结束当前的事物]
 * 	COMMIT / ROLLBACK;
 * 手动开启事务:开启事物代码,添加SQL语句,事物提交或者事物回滚!(不推荐)
 */

import com.shayiheng.api.utils.JdbcUtilsV2;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 
 */
public class BankDao {
   /**
    * 加钱的数据库操作方法(jdbc)
    * @param  account 加钱的账号
    * @param  account 价钱的金额
    */
    public void add(String account,int money) throws ClassNotFoundException, SQLException {
     //1 2 接收业务层传来的连接

     Connection connection = JdbcUtilsV2.getConnection();

     //3.编写SQL语句结果,动态的部分使用?代替
     String sql= "update t_bank set money = money + ? where account= ? ;";
     //4.创建预编译preparedStatement
     PreparedStatement statement = connection.prepareStatement(sql);
     //5.占位符赋值
     statement.setObject(1,money);
     statement.setObject(2,account);
     //6.发送sql语句
     statement.executeUpdate();
     //7.关闭资源
     statement.close();

     System.out.println("加钱成功");
    }

    /**
     * 加钱的数据库操作方法(jdbc)
     * @param  account 减钱的账号
     * @param  account 减钱的金额
     */
    public void sub(String account,int money) throws ClassNotFoundException, SQLException {
     //1 2 接收业务层传来的连接
     Connection connection = JdbcUtilsV2.getConnection();

     //3.编写SQL语句结果,动态的部分使用?代替
     String sql= "update t_bank set money = money - ? where account= ? ;";
     //4.创建预编译preparedStatement
     PreparedStatement statement = connection.prepareStatement(sql);
     //5.占位符赋值
     statement.setObject(1,money);
     statement.setObject(2,account);
     //6.发送sql语句
     statement.executeUpdate();
     //7.关闭资源
     statement.close();
     System.out.println("减钱成功");
    }
}
package transactionnew;

import com.shayiheng.api.utils.JdbcUtilsV2;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @Author Tom
 * @Date 2023/12/22 13:58
 * @Description: 银行卡业务方法,调用dao方法
 */
public class BankServer {
    @Test
    public void start() throws SQLException, ClassNotFoundException {
        //二狗子给lu蛋蛋转500
        transfer("ergouzi","e",500);
    }
    //在业务开启事务
    public void  transfer(String addAccount,String subAccount,int money) throws SQLException, ClassNotFoundException {
        BankDao bankDao = new BankDao();
        Connection connection = JdbcUtilsV2.getConnection();
        try{
            //开启事务 MYSQL会自动事物提交,给它关闭就行
            connection.setAutoCommit(false);
            //执行数据库动作
            //执行数据库动作
            bankDao.add(addAccount,money);
            System.out.println("----------");
            bankDao.sub(subAccount,money);
            //事物提交
            connection.commit();
        }catch (Exception e){
            //事物回滚
            connection.rollback();
            //抛出异常
            throw  e;
        }finally {
            JdbcUtilsV2.freeConnection();
        }
    }
}

文章来源:https://blog.csdn.net/Sakura_syh/article/details/135166499
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。