事物以及事物隔离线的代码详解

前言

不多bb了,直接上代码和注释,看不懂的找博主

数据库初始状态

   //数据库中 id = 1 name = 0000 balance = 2222
   //数据库中 id = 2 name = aaaa balance = null

   //other id = 1 name = AAAA
   //other id = 2 name = BBBB
        

总结:

1、事物开启的时间

如果service中即使一开始就表明了执行事物,但是事物开启的时间也要算在执行数据库语句的时候开开始

举例:一开始表1中name为0000,打上断点,先进入service,不执行sql语句。这个时候手动修改数据库中的name为1111,再执行查询语句,我们会发现取到了那么为1111的值,而不是0000(安装可重复读取的思想解决)(不论是可重复读REPEATABLE_READ还是不可重复读READ_COMMITTED

如果是更新操作,我们在当前事物中进行了更新操作,其他事物更新相同id的数据,则其他事物不能修改,因为更新操作会将这条数据锁住,其他事物不能执这条id的数据,其他的id是可以任意修改的的,除非等当前事物执行完成或者当前事物回滚(总之就是当前事物结束)

2、可重复读取REPEATABLE_READ

事物开始执行的时候,相当于我们将数据库中进行了一个拍照,不论其他事物修改了其他或者本表任何表的任何数据,我们通过find看到的数据都是拍照的数据,也就是说即使其他事物对我们拿到的数据进行了更新,或者添加了新的数据,我们还是看不到。我们只能拿到照片中的数据。


3、不可重复读READ_COMMITTED 一般情况下建议使用

1、只要不是我们从当前事物中取到的数据,其他事物修改了其他或者本表任何表的任何数据,我们查询的话,就是显示最新的数据


2、如果我们正在执行的事物取到了数据,即使别的事物修改成什么样子,我们再查询的话,还是一样的(不管是hibernate查询还是sql查询),相当于只给我们当前查询过的数据拍了照片(其实这个是我实际项目中得到的结果,但是关于网上给出的其他事物修改提交了,这里再次执行,应该是得到最新的数据)

4、update操作和重新赋值给另一个对象实体中内容变化不变化

update 原生 sql语句不会更新当前实体对象,
如果是一个根据id 进行更新,并且返回了结果 ,hibernate的操作会即使重新new一个对象出来也会对原理的对象 进行更新


        DemoEntity demoEntity =  demoEntityRepository.findOne(id);



    isolationService.updateName(id,"zhang123456" ); 
    
    @Modifying
    @Query("UPDATE  DemoEntity  d set d.name = ?2 where d.id = ?1")
    int updateName(Long id ,String name);
    
    //即使重新赋值了新对象one,上面的demoEntity 也会跟着变化,一个事物中的数据,具有连贯性,update语句,则是返回了一个当前行。
    
            DemoEntity one = isolationService.transRequirs(1L,"transRequirsOne");

    
    


下面主要是可重复读取的数据

package com.hlj.springboot.dome.common.moudle.service;

import com.hlj.springboot.dome.common.entity.DemoEntity;
import com.hlj.springboot.dome.common.entity.OtherEntity;
import com.hlj.springboot.dome.common.entity.repository.DemoEntityRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 作者 :HealerJean
 * 日期 :2019/1/23  下午8:02.
 * 类描述:
 */
@Service
public class IsolationStartService {

    @Resource
    private DemoEntityRepository demoEntityRepository ;

    @Resource
    private IsolationService isolationService ;


    @Transactional(isolation = Isolation.READ_COMMITTED ,propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public DemoEntity startTransactional(Long id) {

        //数据库中 id = 1 name = 0000 balance = 2222
        //数据库中 id = 2 name = aaaa balance = null

        //other id = 1 name = AAAA
        //other id = 2 name = BBBB

        //这个时候修改id为1的name为1111,以下查询还没有开启,表明我们的事物目前为止其实还没有开启,因为没有涉及到数据库的操作,有了数据库操作,才会真正开启事物
        DemoEntity demoEntity =  demoEntityRepository.findOne(id);
        demoEntity.setName("startTransactional"); //还没有保存到数据库中,因为事物还没有提交,方法运行结束才会提现目前开启的这个事物,除非中间出现独立事物
        System.out.println(demoEntity);     //DemoEntity(id=1, name=startTransactional, balance=2222)

        //开始独立事物直接保存数据,直接在数据库中有显示
        DemoEntity transRequirsNew =   isolationService.transRequirsNew(id,"transRequirsNew");
        System.out.println(transRequirsNew); //DemoEntity(id=1, name=transRequirsNew, balance=2222)

        //解释:即使独立事物修改过,我们这里还是不会变,还是本事物中的数据(因为是两个事物,具有隔离性)
        System.out.println(demoEntity);  //DemoEntity(id=1, name=startTransactional, balance=2222)

        //当前事物下保存数据,上面的额startTransactional 事物还没有提交,所以和一开始的状态是一致的
        demoEntity = isolationService.transRequirs(id,"transRequirs");
        System.out.println(demoEntity) ; //DemoEntity(id=1, name=transRequirs, balance=2222)

        // 目前,直接看数据库中,name应该能是transRequirsNew, 手动修改数据库中的 name为 3333
        //读取已经提交的数据,这里没有开启独立事物,所以即使配置了,读已提交也不会生效,因为再我们这个方法一开始的时候,就已经确定了隔离性质
        demoEntity = isolationService.isoLationReadCommitedFind(id);
        System.out.println(demoEntity); // DemoEntity(id=1, name=transRequirs, balance=2222)



        // 可重复读 这个时候我们修改 2中的数据为 bbbb,会发现这个时候查询的时候,下面还为aaa ,
        // READ_COMMITTED 可重复读取:修改了之后,我们查询到的数据库是bbbb,说明READ_COMMITTED 生效了
        DemoEntity two = isolationService.transRequirsFind(2L);
        System.out.println(two) ;
        //可重复读          DemoEntity(id=2, name=aaaa, balance=null)
        //READ_COMMITTED   DemoEntity(id=2, name=bbbb, balance=null)


        //下面一起修改了即使换一个变量名字,demoEntity的变量还是会跟着变的
        DemoEntity one = isolationService.transRequirs(1L,"transRequirsOne");
        System.out.println(one) ; //DemoEntity(id=1, name=transRequirsOne, balance=2222)
        System.out.println(demoEntity) ; //DemoEntity(id=1, name=transRequirsOne, balance=2222)

        //可重复读 这个时候直接修改 这张表中的数据为CCCC,我们会发现本事物中查询的还是之前的结果AAAA,说明本事物开启之后,就会对数据库中的数据进行锁定(相当于是拍了张照片)
        //READ_COMMITTED 这个时候直接修改数据库 这张表中的数据为CCCC, 这里查询得到的是CCCC,说明不可重复读生效了
        OtherEntity otherEntity = isolationService.findOther(1L);
        System.out.println(otherEntity);
        //可重复读 OtherEntity(id=1, name=AAAA)
        //READ_COMMITTED OtherEntity(id=1, name=CCC)


        //可重复读 这个时候直接修改 这张表中的数据为DDDD,我们会发现本事物中查询的还是之前的结果BBBB
        //READ_COMMITTED 这个时候直接修改数据库 这张表中的数据为CCCC, 这里查询得到的是CCCC,说明不可重复读生效了
        OtherEntity otherEntityTwo = isolationService.findOther(2L);
        System.out.println(otherEntityTwo);
        //可重复读 OtherEntity(id=2, name=BBBB)
        //READ_COMMITTED OtherEntity(id=2, name=DDDD)


        //指定id更新不会影响demoEntity 现在的数据
        isolationService.updateName(id,"zhang123456" );
        System.out.println(demoEntity); //DemoEntity(id=1, name=transRequirsOne, balance=2222)

        System.out.println(transRequirsNew);//DemoEntity(id=1, name=transRequirsNew, balance=2222)
        return demoEntity;

        //上面两种的最终数据库中就 都变成了
        // id =1 name= zhang123456  balance = 2222
        // id =2 name= bbb balance = nulll

        //other表 id= 1 name =CCCC
        //id = 2 name =DDDD
    }


}



1、接口

package com.hlj.springboot.dome.common.moudle.service;

import com.hlj.springboot.dome.common.entity.DemoEntity;
import com.hlj.springboot.dome.common.entity.OtherEntity;

/**
 * 作者 :HealerJean
 * 日期 :2019/1/23  下午7:34.
 * 类描述:
 */
public interface IsolationService {



    /**
     * 方法中的事物为入口方法的事物
     * @param id
     * @return
     */
    DemoEntity  transRequirs(Long id,String name);
    DemoEntity  transRequirsFind(Long id);

    /**
     * 开启一个事物
     * @param id
     * @return
     */
    DemoEntity  transRequirsNew (Long id,String name);


    /**
     * 事物隔离级别为 读已提交()
     * @param id
     * @return
     */
    DemoEntity   isoLationReadCommitedFind(Long id) ;


    int updateName(Long id,String name);


    OtherEntity findOther(Long id);

}

3、接口实现类

package com.hlj.springboot.dome.common.moudle.service.impl;

import com.hlj.springboot.dome.common.entity.DemoEntity;
import com.hlj.springboot.dome.common.entity.OtherEntity;
import com.hlj.springboot.dome.common.entity.repository.DemoEntityRepository;
import com.hlj.springboot.dome.common.entity.repository.OtherEntityRepository;
import com.hlj.springboot.dome.common.moudle.service.IsolationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 作者 :HealerJean
 * 日期 :2019/1/23  下午7:35.
 * 类描述:
 */
@Service
@Slf4j
public class IsolationServiceImpl  implements IsolationService {

    @Resource
    private DemoEntityRepository demoEntityRepository ;

    @Resource
    private OtherEntityRepository otherEntityRepository ;


    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public DemoEntity transRequirs(Long id,String name) {
        DemoEntity demoEntity =  demoEntityRepository.findOne(id);
         demoEntity.setName(name);
        return demoEntityRepository.save(demoEntity);
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public DemoEntity transRequirsFind(Long id) {
        return demoEntityRepository.findOne(id);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    @Override
    public DemoEntity transRequirsNew(Long id,String name) {
        DemoEntity demoEntity =  demoEntityRepository.findOne(id);
        demoEntity.setName(name);
        return demoEntityRepository.save(demoEntity);
    }

    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public DemoEntity isoLationReadCommitedFind(Long id) {
        return demoEntityRepository.findOne(id);
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int updateName(Long id, String name) {
        return demoEntityRepository.updateName(id,name);
    }


    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public OtherEntity findOther(Long id) {
        return otherEntityRepository.findOne(id);
    }
}





感兴趣的,欢迎添加博主微信,

哈,博主很乐意和各路好友交流,如果满意,请打赏博主任意金额,感兴趣的在微信转账的时候,备注您的微信或者其他联系方式。添加博主微信哦。


请下方留言吧。可与博主自由讨论哦

微信 微信公众号 支付宝
微信 微信公众号 支付宝
posted @ 2019-01-24 20:20  HealerJean  阅读(110)  评论(0编辑  收藏  举报