• HIbernate学习笔记(九) hibernate事务并发处理与乐观悲观锁


    事务并发处理

    一、 数据库的隔离级别:并发性作用。

    1、   ReadUncommited(未提交读):没有提交就可以读取到数据(发出了Insert,但没有commit就可以读取到。)很少用

    2、   ReadCommited(提交读):只有提交后才可以读,常用,

    3、   RepeatableRead(可重复读):mysql默认级别, 必需提交才能见到,读取数据时数据被锁住。

    4、   Serialiazble(序列化读):最高隔离级别,串型的,你操作完了,我才可以操作,并发性特别不好,

    隔离级别

    是否存在脏读

    是否存在不可重复读

    是否存在幻读

    Read Uncommitted(未提交读)

    Y

    Y

    Y

    Read Commited(提交读)

    N

    Y(可采用悲观锁解决)

    Y

    Repeatable Read(可重复读)

    N

    N

    Y

    Serialiazble(序列化读)

     

     

     

     

     

     

     

     

     

     

    脏读:没有提交就可以读取到数据称为脏读

    不可重复读:再重复读一次,数据与你上的不一样。称不可重复读。

    幻读:在查询某一条件的数据,开始查询的后,别人又加入或删除些数据,再读取时与原来的数据不一样了。

    1、   Mysql查看数据库隔离级别:

    方法:select@@tx_isolation;

    2、   Mysql数据库修改隔离级别:

    方法:set transactionisolation level 隔离级别名称;

    例如:修改为未提交读:settransaction isolation level read uncommitted;

    二、 事务概念(ACID)

    ACID即:事务的原子性、一致性、独立性及持久性 
    事务的原子性:是指一个事务要么全部执行,要么不执行.也就是说一个事务不可能只执行了一半就停止了.比如你从取款机取钱,这个事务可以分成两个步骤:1划卡,2出钱.不可能划了卡,而钱却没出来.这两步必须同时完成.要么就不完成.
    事务的一致性:是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.
    事务的独立性:是指两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致. 
    事务的持久性:是指事务运行成功以后,就系统的更新是永久的.不会无缘无故的回滚.

    三、 事务并发时可能出现问题

    1、第一类丢失更新(Lost Update)

    时间

     hibernate悲观锁、乐观锁

    Hibernate谈到悲观锁、乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差

             并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了。称为并发性不好

        数据库隔离级别:见前面章级

    一、 悲观锁

    悲观锁:具有排他性(我锁住当前数据后,别人看到不此数据)

    悲观锁一般由数据机制来做到的。

    1、   悲观锁的实现

    通常依赖于数据库机制,在整修过程中将数据锁定,其它任何用户都不能读取或修改(如:必需我修改完之后,别人才可以修改)

    2、   悲观锁的适用场景:

    悲观锁一般适合短事务比较多(如某一数据取出后加1,立即释放)

    长事务占有时间(如果占有1个小时,那么这个1小时别人就不可以使用这些数据),不常用。

    3、   实例:


    yon

    用户1、用户2 同时读取到数据,但是用户2先 -200,这时数据库里的是800,现在用户1也开始-200,可是用户1刚才读取到的数据是1000,现在用户用刚刚一开始读取的数据1000-200为800,而用户1在更新时数据库里的是用房更新的数据800,按理说用户1应该是800-200=600,而现在是800,这样就造成的更新丢失。这种情况该如何处理呢,可采用两种方法:悲观锁、乐观锁。先看看悲观锁:用户1读取数据后,用锁将其读取的数据锁上,这时用户2是读取不到数据的,只有用户1释放锁后用户2才可以读取,同样用户2读取数据也锁上。这样就可以解决更新丢失的问题了。

    实体类:

    public class Inventory {

        private int itemNo;

        privateString itemName;   

        private int quantity;

        public intgetItemNo() {

            return itemNo;

        }

        public voidsetItemNo(intitemNo) {

            this.itemNo =itemNo;

        }

        publicString getItemName() {

            return itemName;

        }

        public voidsetItemName(String itemName) {

            this.itemName =itemName;

        }

        public intgetQuantity() {

            return quantity;

        }

        public voidsetQuantity(intquantity) {

            this.quantity =quantity;

        }  

    }

    映射文件:

    <hibernate-mapping>

        <class name="com.wjt276.hibernate.Inventory"table="t_inventory">

            <id name="itemNo">

                <generator class="native"/>

            </id>

            <property name="itemName"/>

            <property name="quantity"/>

        </class>

    </hibernate-mapping>

    4、   悲观锁的使用

    如果需要使用悲观锁,肯定在加载数据时就要锁住,通常采用数据库的for update语句。

    Hibernate使用Load进行悲观锁加载。

    Session.load(Classarg0, Serializable arg1, LockMode arg2) throws HibernateException

    LockMode:悲观锁模式(一般使用LockMode.UPGRADE)

    session= HibernateUtils.getSession();

                tx = session.beginTransaction();

                Inventory inv =(Inventory)session.load(Inventory.class, 1,LockMode.UPGRADE);

                System.out.println(inv.getItemName());

                inv.setQuantity(inv.getQuantity()-200);

               

                session.update(inv);

                tx.commit();

    5、   执行输出SQL语句:

    Hibernate:select inventory0_.itemNo as itemNo0_0_, inventory0_.itemName as itemName0_0_,inventory0_.quantity as quantity0_0_ from t_inventory inventory0_ where inventory0_.itemNo=?for update //在select语句中加入for update进行使用悲观锁。

    脑白金

    Hibernate:update t_inventory set itemName=?, quantity=? where itemNo=?

    注:只有用户释放锁后,别的用户才可以读取

     

    注:如果使用悲观锁,那么lazy(悚加载无效)

    二、 乐观锁

    乐观锁:不是锁,是一种冲突检测机制。

         乐观锁的并发性较好,因为我改的时候,别人随边修改。

         乐观锁的实现方式:常用的是版本的方式(每个数据表中有一个版本字段version,某一个用户更新数据后,版本号+1,另一个用户修改后再+1,当用户更新发现数据库当前版本号与读取数据时版本号不一致(等于小于数据库当前版本号),则更新不了。

             Hibernate使用乐观锁需要在映射文件中配置项才可生效。

    实体类:

    public classInventory {

        private int itemNo;

        privateString itemName;   

        private int quantity;  

        private int version;//Hibernate用户实现版本方式乐观锁,但需要在映射文件中配置

        public intgetItemNo() {

            return itemNo;

        }

        public voidsetItemNo(intitemNo) {

            this.itemNo =itemNo;

        }

        publicString getItemName() {

            return itemName;

        }

        public voidsetItemName(String itemName) {

            this.itemName =itemName;

        }

        public intgetQuantity() {

            return quantity;

        }

        public voidsetQuantity(intquantity) {

            this.quantity =quantity;

        }

        public intgetVersion() {

            return version;

        }

        public voidsetVersion(intversion) {

            this.version =version;

        }

    }

    映射文件

    <hibernate-mapping>

    <!-- 映射实体类时,需要加入一个开启乐观锁的属性

    optimistic-lock="version" 共有好几种方式:

        - none  -version   - dirty - all

        同时需要在主键映射后面映射版本号字段

        -->

    <class name="com.wjt276.hibernate.Inventory"table="t_inventory"optimistic-lock="version">

            <id name="itemNo">

                <generator class="native"/>

            </id>

            <version name="version"/><!—必需配置在主键映射后面 -->

            <property name="itemName"/>

            <property name="quantity"/>

        </class>

    </hibernate-mapping>

    导出输出SQL语句:

    createtable t_inventory (itemNo integer not null auto_increment, versioninteger not null, itemName varchar(255), quantity integer,primary key (itemNo))

    注:添加的版本字段version,还是我们来维护的,是由hibernate来维护的。

    乐观锁在存储数据时不用关心

  • 相关阅读:
    使用树莓派打造一个音乐播放器
    关于ESP8266 NodeCMU固件无法刷入新代码的解决方法
    推荐一个好用的免费开源的笔记本软件CherryTree
    忘记数据库密码?通过Navicat找回!!
    Kettle删除日志文件
    windows下解决10点前生成时间命名的文件无效问题
    windows下备份Linux服务器上的MySQL
    Windows下安装mysql
    【EXCEL】按天计算,分摊到每年的费用金额,只用内置函数 无需编写VB
    windows 7 安装visual studio 2019 闪退问题解决
  • 原文地址:https://www.cnblogs.com/hustfly/p/3454586.html
Copyright © 2020-2023  润新知