Java简单演示悲观锁

Java简单演示悲观锁


每博一文案

看过这样一句话,时间在不断的筛选你身边的人和事。当你什么都不在乎的时候,你的人生才刚刚开始。
当我们什么都不在乎时,会发现什么都可能会进行经历,但什么都一定会过去,起始都会离开的或早或晚吧了。
道德经中说:“飘风不终朝,骤雨不终日“,生活本来没有那么沉重,一味的与自己较劲,只会作茧自缚,
折磨你的从来不是任何热的情绪,而是你心存幻想的期待。
世间万物都在治愈你,但唯独你自己,不可放过自己,你涉水而过,但不代表拥有这条河,越是执着,哪些
给你带来快乐的人,事,物,其带来的痛苦就越大,不要把怀念,弄得比过程还长。
怀念时一种惩罚,惩罚哪些喜欢念旧的人。要知道钟表能回到起点,但是回不到昨天,你应该让自己变好,
而不是沉寂在,这段不闻不问的日子里,与其纠结往事,越陷越深,不如试着与它和解,别和往事过不去,因为他已经过去,别和现实过不去,因为你还要过下去,意味的偏执,往往会将自己的救赎越埋越深。
世上千灯万盏,不如心灯一盏。心若盛开,一念起风声鹤唳,一念灭繁花似锦。
大风遥遥,有人告别,有人伫立。暮色长凝,有人点灯,有人熄。花开花落自有时,别问这人间值不值得。
安然过冬,来年一定又是好春光。
愿你得失随缘,自在随心,往事的背后疗伤,在人来人往中坚强。
                                    ——————   一禅心灵庙语1


悲观锁

顾名思义,就是比较悲观的锁,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

在Mysql当中只需要在 select 查询的结果后面加上 for update其查询的结果就被锁上了。如果本次事务没有被 commit 提交给数据库,则其他事务就无法修改:下面我们对 tests 数据表进行一个悲观锁的控制

在这里插入图片描述

在这里插入图片描述


下面是两段Java中使用悲观锁的演示:

在这里插入图片描述

在这里插入图片描述

package Blogs.blogs04;

import java.sql.*;

public class LockTest {

    public static void main(String[] args) {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;  // 扩大作用域,用于关闭资源


        try {
            // 1. 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.连接驱动中的数据库,url中的 localhost 可以省略为 ///dbtest
            connection = DriverManager.getConnection("jdbc:mysql:///dbtest6","root","MySQL123");

            connection.setAutoCommit(false);  // 取消自动提交数据,开启事务

            // 3. 获取操作数据库的(预编译)对象
            String sql = "select id,name from tests where id = ? for update";  // for update 悲观锁
            preparedStatement = connection.prepareStatement(sql);  // 预编译对象

            // 填充占位符
            preparedStatement.setInt(1,1);  // 占位符的填充从起始下标 1 开始

            // 4.执行sql语句
            resultSet = preparedStatement.executeQuery();

            // 处理select 查询的结果集
            while(resultSet.next()) {  // 判断该行记录是否有数据有,返回true并向下移动,没有返回false
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);

                System.out.println(id+"=>"+name);
            }

            connection.commit();  // 手动提交数据信息
        } catch (Exception e) {
            if(connection != null) {
                // 出现异常,回滚事务
                try{
                    connection.rollback();  // 事务的回滚
                } catch(SQLException E) {
                    throw new RuntimeException (E);  // 将编译异常转换为运行异常抛出
                }
            }
            throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
        } finally {
            // 6.关闭资源,最晚使用的最先关闭
            if(resultSet != null) {  // 防止空引用
                try{
                    resultSet.close();   // 释放处理select 查询结果集的资源
                }catch(SQLException e) {
                    throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
                }
            }


            if(preparedStatement != null) {
                try{
                    preparedStatement.close();  // 释放操作数据库的资源
                } catch (SQLException e) {
                    throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
                }
            }

            if(connection != null) {
                try {
                    connection.close();  // 关闭数据库连接
                } catch (SQLException e) {
                    throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
                }
            }


        }


    }
}

package Blogs.blogs04;

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

public class LockTest2 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null; // 扩大作用域,用于关闭资源

        try {
            // 1. 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.连接驱动上的数据库
            connection = DriverManager.getConnection("jdbc:mysql:///dbtest6","root","MySQL123");

            connection.setAutoCommit(false); // 取消自动提交数据,开启事务

            // 3. 获取到操作数据库的对象(预编译sql语句对象)
            String sql = "update tests set name = ? where id = ?";  // 占位符不要加单引号,不然就成字符串了
            preparedStatement = connection.prepareStatement(sql);  // 仅仅只是预编译sql语句

            // 填充占位符(在预编译之后,防止sql注入),起始下标是从 1 开始的
            preparedStatement.setString(1,"Tom");
            preparedStatement.setInt(2,1);

            // 4.执行sql语句
            int count = preparedStatement.executeUpdate(); // 返回影响数据库的行数(注意是无参的,因为上面我们已经编译过了)
            System.out.println("影响数据库的行数: "+count);

            connection.commit();  // 手动提交数据

            // 5. 处理select 查询的结果集,这里不是
        } catch (Exception e) {
            // 发生异常,回滚事务
            if(connection != null) {  // 防止null引用
                try {
                    connection.rollback();
                } catch (SQLException E) {
                    throw new RuntimeException (E);  // 将编译异常转换为运行异常抛出
                }
            }
            throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
        } finally {
            // 6.关闭资源,最晚使用的最先关闭资源
            if(preparedStatement != null) {
                try{
                    preparedStatement.close();  // 释放操作数据库的资源
                } catch (SQLException e) {
                    throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
                }
            }

            if(connection != null) {
                try {
                    connection.close();  // 关闭数据库连接
                } catch (SQLException e) {
                    throw new RuntimeException (e);  // 将编译异常转换为运行异常抛出
                }
            }
        }


    }
}


总结:

悲观锁:如果一个 select 查询的结果集附加上 for update (就会被悲观锁,锁住),当这个事务没有手动提交 commit 数据结束,其他事务是无法对 select 查询结果集锁住的数据进行一个修改的,但只有悲观锁的事务 commit 提交了,就可以更改了。

最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!。最后,朋友,请留下你来过的证明 。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值