案发现场

//防止全局配置了 所以这里定义sprnig 不托管事物
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public boolean deductNumber(Long id,int i){ DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);//设置事物传播行为
TransactionStatus status = null;
try {
//开启事物
status = transactionManager.getTransaction(def);
if(id==null){
return false;//库存编号不能为空
}
if(i<=0){
return false;//扣除库存不能小于0
}
//提交事务
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
return false;
}
return true;
}

导致问题

线上出现 订单下单 提示用户订单创建成功  但是订单不在了 对应的钱没扣 库存也没扣   看代码没有问题 日志也是正常打印 没抛错没回滚

mysql 部分表出现锁等待 单表操作无并发也出现锁等待

自己的坑自己填

1.day 1

怀疑是数据库的问题 事物提交了 但是数据库没持久  在下单操作打印了日志判断是否回滚并打印日志

if(status.isRollbackOnly()){
logger.info("======事物已回滚=========");
return false;
}

2.day 2

第二天又出现这种情况 同时发现伴随着后台有个事物一一直 在select * from information_schema.innodb_trx; runing 持续半个小时以上

但是发现丢单的地方======事物已回滚========

这个时候很疑惑 因为下单很多逻辑怀疑是某个方法设置了回滚状态但是抛出true  来log4j开启事物管理器debug日志

log4j.logger.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG

开启之后开启事物 设置事物状态合并事物都会打印对应的日志
同时为了定位到runing的事物是在哪个地方 在重写了log4j layout 打印了事物号和线程号

log4j配置log4j.appender.stdout.layout =com.chinayanghe.dms.log4jUtil.MyPatternLayout

public class MyPatternLayout extends PatternLayout {
/**
* 日志打印
*/
protected Logger logger = LoggerFactory.getLogger(getClass());
private static ThreadLocal<String> localTreadIds = new ThreadLocal<String>(); public static void removeTreadLocalCache() {
localTreadIds.remove();
}
@Override
public String format(LoggingEvent event) {
String logStr = super.format(event);
try {
if (logStr.indexOf("SELECT trx_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID()") < 0
&&logStr.indexOf("SELECT trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();")<0) {
//表示是sql打印尝试获得事物号
if (logStr.indexOf("[org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:145)] ==> Preparing:") >= 0) { WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
String treadId = localTreadIds.get();
if (StringUtil.isEmpty(treadId)) {
JDBCTransactionInfoService jdbcTransactionInfoService = (JDBCTransactionInfoService) wac.getBean("jDBCTransactionInfoServiceImpl");
List<String> treadIds = jdbcTransactionInfoService.selectTrxMysqlThreadId();
if (CollectionUtils.isNotEmpty(treadIds)) {
treadId = treadIds.get(0);
localTreadIds.set(treadId);
}
}
if (treadId != null) {
logStr = logStr.replace("[DEBUG]", "[DEBUG][事务号" + treadId + "]");
} } else if (logStr.indexOf("Transactional code has requested rollback") >= 0) {
logStr = logStr.replace("Transactional code has requested rollback", "Transactional code has requested rollback,线程id:" + Thread.currentThread().getId());
}
} else {
return "";
}
long treadId = Thread.currentThread().getId();
logStr = logStr.replace("[DEBUG]", "[DEBUG][线程id:" + Thread.currentThread().getId() + "]").replace("[INFO]", "[INFO][线程id:" + treadId + "]");
} catch (Exception e) {
logger.info(e.getMessage());
}
return logStr;
}
}

3.day3出现丢单根据日志发现 丢单的都是同一个线程id 事物号也相同  同时丢单的地方都没有开启事物日志而是事物已存在合并的日志

根据日志 一个一个看 发现规律 线程id最后一次打印 creating transaction  之后 再也没打印  然后定位到最后一次打印事物 的方法是手动开启事物的方法  有个地方忘记回滚 直接return了

这个时候反应过来 是这个方法没提交一直挂起  spring事物是基于线程缓存 tomcat会回收线程到线程池  下单分配到这个线程  因为手动开启事物还存在 所以公用同一个事物  事物一致挂起 当遇到RR模式锁等待抛出wai lock

statu的回滚状态会设置为true 所以才会出现我的下单日志打印都是回滚

优化代码

 //防止全局配置了 所以这里定义sprnig 不托管事物
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public boolean deductNumber(Long id,int i){ DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);//设置事物传播行为
TransactionStatus status = null;
try {
//开启事物
status = transactionManager.getTransaction(def);
if(id==null){
transactionManager.rollback(status);
return false;//库存编号不能为空
}
if(i<=0){
return false;//扣除库存不能小于0
}
//提交事务
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
return false;
}finally {
//加上此代码 防止忘记
if(status!=null&&!status.isCompleted()){
transactionManager.rollback(status);
return false;
}
} return true;
}

总结原因:

事物一直没有被提交,事物状态是通过线程缓存实现的,当线程回收到线程池,后面再分分派的这个线程使用的同一个连接和事物,事物其实一直挂起

oracle大数据量。表分区提示查询效率的更多相关文章

  1. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  2. Oracle大数据量查询实际分析

    Oracle数据库: 刚做一张5000万条数据的数据抽取,当前表同时还在继续insert操作,每分钟几百条数据. 该表按照时间,以月份为单位做的表分区,没有任何索引,当前共有14个字段,平均每个字段3 ...

  3. (转)SqlServer为大数据量表建索引

    本文转载自:http://blog.csdn.net/iangujun/article/details/8136764 之前从没有用SqlServer数据库处理过大数据量的表,都是用Oracle,然后 ...

  4. 大数据量表中,增加一个NOT NULL的新列

      这次,发布清洗列表功能,需要对数据库进行升级.MailingList表加个IfCleaning字段,所有的t_User*表加个IfCleaned字段.   脚本如下 对所有的t_User表执行 a ...

  5. 大数据量下DataTable To List效率对比

    使用反射和动态生成代码两种方式(Reflect和Emit) 反射将DataTable转为List方法 public static List<T> ToListByReflect<T& ...

  6. oracle大数据量更新引发的死锁问题解决方法及oracle分区和存储过程的思考

    前言 前几天上午在对数据库的一张表进行操作的时候,由于这张表是按照时间的一张统计表,正好到那天没有测试数据了,于是我想将表中所有的时间,统一更新到后一个月,于是对80w条数据的更新开始了.整个过程曲折 ...

  7. ORACLE中大数据量查询实现优化

    大数据量查询,对数据库开发者来说,性能问题往往是最需要费尽心机的,借此总结自己优化此类问题的心得与大家分享,以免大家走更多的弯路. 1.使用主键临时表 大数据量表关联查询,是性能开销的主要原因.通过主 ...

  8. java大数据量调优

    从总体上来看,对于大型网站,比如门户网站,在面对大量用户访问.高并发请求方面,基本的解决方案集中在这样几个环节:1.首先需要解决网络带宽和Web请求的高并发,需要合理的加大服务器和带宽的投入,并且需要 ...

  9. Oracle大数据常见优化查询

    [转]http://www.cnblogs.com/myhappylife/p/5006774.html 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的 ...

随机推荐

  1. delphi附带通用控件安装方法:

    附带通用控件安装方法:----------基本安装1.对于单个控件,Componet-->install component..-->PAS或DCU文件-->install;2.对于 ...

  2. SPM - data analysis

    来源: SPM基本原理与使用PPT, 北师大,朱朝喆研究员,http://www.cnblogs.com/haore147/p/3633515.html ❤ First-level analysis: ...

  3. mybatis 3.2.7 与 spring mvc 3.x、logback整合

    github上有一个Mybatis-Spring的项目,专门用于辅助完成mybatis与spring的整合,大大简化了整合难度,使用步骤: 准备工作: maven依赖项: <properties ...

  4. Spring 4.0.2 学习笔记(1) - 最基本的注入

    1. 添加maven支持 <dependency> <groupId>org.springframework</groupId> <artifactId> ...

  5. 【福吧资源网整理】老男孩-python运维6期 不加密

    老男孩-python运维6期 不加密,连夜整理出来分享给大家老男孩的python教程确实不错. 教程目录: 下载地址:http://www.fu83.cn/thread-204-1-1.html  

  6. ubuntu 安装VmTool

    VM tools 是Vmware的一组工具.主要用于虚拟主机显示优化与调整,另外还可以方便虚拟主机与本机的交互,如允许共享文件夹,甚至可以直接从本机向虚拟主机拖放文件.鼠标无缝切换.显示分辨率调整等, ...

  7. 你是否还在质疑EF的性能

    1. 写在前面的话 一直没有写博客的习惯,感觉太浪费时间,没有那么多精力,其实仔细一想,写博客是一种习惯,也是一种心境,同时也是对自己所掌握的知识结构的一个梳理过程,对自己知识体系的一个巩固,同时也是 ...

  8. 深入理解计算机系统(1.2)---hello world的程序是如何运行的

    在写本章的内容之前,LZ先做个小广告.其实也不算是什么广告,就是LZ为了和各位猿友交流方便,另外也确实有个别猿友留言或者在博客里发短消息给LZ要联系方式.因此LZ斗胆建立了一个有关<深入理解计算 ...

  9. [BZOJ 1997][HNOI2010]Planar(2-SAT)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1997 分析: 考虑每条边是在圈子里面还是圈子外面 所以就变成了2-SAT判定问题了= ...

  10. Xen

    Xen是一个开放源代码虚拟机监视器,由剑桥大学开发.它打算在单个计算机上运行多达128个有完全功能的操作系统. 在旧(无虚拟硬件)的处理器上执行Xen,操作系统必须进行显式地修改(“移植”)以在Xen ...