数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)

数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)

一、简单介绍情况

遇到一个项目,框架使用的是SSH,数据库事务是HibernateTransactionManager,感觉维护这个项目的先辈应该是非计算机专业培训班出来的,对数据库事务没有掌握,我正好利用这个修改的机会算是比较全面的理解事务。

这是事务的配置,简单看下,知道大概意思

数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)_第1张图片

切入点的方法是com.fpi.prd.uems包下任何子包任何类任何方法任何参数。

数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)_第2张图片                          数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)_第3张图片

 

项目里基本上符合条件的方法都在这里,其中的我主要研究的方法大家看下

可以看出,事务拦截配置在控制层(@Controller)。

二,下面是我几个关注的地方。

	@RequestMapping("/load/save")
	@ResponseBody
	public JsonMessage save(Model model, TBPomsWater item,
			@RequestParam(value = "letPortInfoId", required = false) String letPortInfoId,
			@RequestParam(value = "checkManIds", required = false) String checkManIds,
			@RequestParam(value = "checkMans", required = false) String checkMans) {
		JsonMessage msg = new JsonMessage(true, "保存成功!");
		item.settBPomsCompany(CompanyManager.getInstance().getCompanyByAllById(item.getTBPomsCompany().getId()));
		// 业务代码无关紧要删了
		String siteId = item.getId();
		try {
			if (StringUtils.isEmpty(siteId)) {
				/**
				 * 这里我加了判断代码,保存前后,查询到的数据,listOfAfter的确增加了1
				 */
				List listOfBefore = commonService.getEntityList(TBPomsWater.class);
				siteId = commonService.save(item);
				List listOfAfter = commonService.getEntityList(TBPomsWater.class);
				/* 添加排口相关的运维任务配置 */
				InspectionConfig inspectionConfig = new InspectionConfig();
				//业务代码无关紧要删了
	/**
				 * 这里我加了判断代码,保存前后,查询到的数据,listOfAfter的确增加了1
				 */
				List list1 = commonService.getEntityList(InspectionConfig.class);
				commonService.save(inspectionConfig);
				List list2 = commonService.getEntityList(InspectionConfig.class);
				/**
				 * 这里应该也不会起作用,这里起作用了,说明同一个线程里(同一事务),是可以获取同一事务实时更新的数据的
				 */
				InspectionConfigManager.reset();
			} else {
				commonService.update(item);
			}
			/**
			 * 异常出去,观察事务是否起作用,应该是会保存成功
			 */
			int a= 1/0;
		} catch (Exception e) {
			msg = new JsonMessage(false, "保存失败");
		}
		/**
		 * 20190718,因为事务的原因(好像这里的事务被try catch了,事务应该也不起作用,事务不会回滚,但是会锁表至请求线程结束)
		 * 导致这里的reset想起的作用(本次更新)没有起作用。需要重新设计
		 * 具体的现象是企业排口信息修改并保存,导出的二维码信息没有跟着更新,需要二次保存,才有效果。
		 * 同一个线程里的方法(也就同一个事务),是可以查询到更新数据的。不同线程是查询不到事务提交,
		 */
		LetportManager.reset();
		return msg;
	}

 

我是发现InspectionConfigManager.reset();起作用了,说明事务虽然未提交,但是同线程内是可以查询到本次事务save更新内容的。然后增加了两处的观察代码,发现这个现象是确定。

数据库事务的理解(同一线程(同一事务),是可以查询到同一事务实时的更新数据,不同线程是不可以访问其他事务实时更新的数据的)_第4张图片

两次保存结果都是可以查询到的,都是增加了1

结论1:说明同一个请求线程里(同一事务),是可以获取本事务实时更新的数据的。

二、这段代码从事务来讲,主要的问题有以下

1是try catch,异常的话事务是不会回滚的。这个大家都知道。

2是InspectionConfigManager.reset()放在事务里,更新缓存是没有意义的,因为事务无论有没有成功提交,都会实时更新缓存。方法大家看下,就是重新采用构造器的方法,重新生成实例,从数据库获取数据,更新。

public  static void reset() {
	instance = new InspectionConfigManager();
}

3.对业务影响最大的问题。LetportManager.reset();这个reset();

public static void reset() {
	LetportManager.staticReset();
	OmsServiceUtil.getAppInspectionService().updateUserImei();
}
public  static void staticReset() {
	instance = null;
}

public  static  LetportManager getInstance() {
	if (instance == null) {
			synchronized(LetportManager.class){
				if (instance == null) {
					instance = new LetportManager();
				}
			}
	}
	return instance;
}

LetportManager 采用的是同步懒汉式的单例。reset的想法就是将instance至为null,后面项目需要的时候会重新生成单例,这就更新了。这个实例太多地方都会用到。在方法没走完,或者走到mvc的handler、DispatcherServlet(这里需要验证,走到哪一步,事务就会提交),其他线程就生成instance,当然这个时候事务是没有提交的,缓存更新是不会成功。两个reset想法相似,实现方式相似,但是结果完全不同,一个是无论成功失败都会实时更新,脏数据。一个是只有万分之一的机会才会更新成功,一旦失败,就需要下次reset,又是万分之一,唯一能百分百成功的,就是重启服务,搞笑吧。

结论二:不同的线程(这里不能说不同事务了),是无法获取到一个事务实时更新的数据的,直到事务提交。

结论三:作为增删改查的码农,还是要对自己的代码负责,想当然的写代码,这个坑会很大。这个坑,在项目里出现的次数保守估计100处以上,修改的话,要修改缓存结构,事务最好配置在事务层,代价很大。

这个是我的判断和结论,可能还不对,需要在以后的遇到再总结出来,不对的地方请前辈指出。

 

 

 

 

你可能感兴趣的:(Java,ssm)