一次野事务排查

测试环境出了一个很神奇的问题。
某一个事务锁了很多不同表的不同记录(暂且先叫他野事务),导致其他事务都阻塞了.
这个野事务往往持续数个小时,并不提交或者回滚,就生生的占在那里。
野事务锁的表,相互之间没有任何的关联.不能定位到某一个业务或者模块.

经过排查,这个问题和我们的开发方式有关系.
虽然使用了Spring,但是居然没有使用Spring的事务管理机制.
绝大多数的数据库操作,都是依赖于自动提交.另外少数的模块,使用了手动开启的编程式事务管理.
但是编程式事务的一个分支判断出现了bug,没有提交事务或者回滚.
导致了这个连接归还连接池之后(这时候这个连接 autocommit尚在false状态)
其他自动提交的模块如果使用这个连接执行,那么就会不断的加锁,而不释放.从而导致一系列怪异神奇的现象.

当时出问题的代码示例如下

  1. public Map<String, Object> xxxMethod(String jsonParam) {  
  2.         BaseParam baseParam = JsonUtil.getObjectFromJson(jsonParam, BaseParam.class);  
  3.         Map<String, Object> bizParamMap = baseParam.getBizParamMap();  
  4.   
  5.         DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
  6.         TransactionStatus status = transactionManager_vvlivemetadata.getTransaction(def);  
  7.         try {  
  8.             UserBaseinfo userBaseinfo = userBaseinfoMapper.selectByPrimaryKey(lineUserID);  
  9.             if (userBaseinfo == null) {  
  10.                 return createFailResult(baseParam, RetEnum.RET_METADATA_USER_NOT_EXISTS);  
  11.             }  
  12.             LiveLineInfo liveLineInfo = new LiveLineInfo();  
  13.             liveLineInfo.setLiveLineID(lineUserList.get(0).getLiveLineID());  
  14.             liveLineInfo.setLiveID(liveID);  
  15.             liveLineInfo.setUserID(userID);  
  16.             liveLineInfo.setLineUserID(lineUserID);  
  17.             liveLineInfo.setStatus((short0);  
  18.             int liveLineInfoRetNum = liveLineInfoMapper.updateByPrimaryKeySelective(liveLineInfo);  
  19.             if (liveLineInfoRetNum != 1) {  
  20.                 transactionManager_vvlivemetadata.rollback(status);// bug  当时没加  
  21.                 _log.error(“取消连麦失败, 房间上麦信息状态修改失败. jsonParam={}, liveLineInfoRetNum={}”,  
  22.                         jsonParam, liveLineInfoRetNum);  
  23.                 return createFailResult(baseParam, RetEnum.RET_DB_FAIL);  
  24.             }  
  25.             liveLineInfoMapper.updateOthersShowPosBatch(liveID, lineUserList.get(0).getShowPos());  
  26.             transactionManager_vvlivemetadata.commit(status);  
  27.             return createBizResult(baseParam, jsonResult);  
  28.         } catch (Exception e) {  
  29.             transactionManager_vvlivemetadata.rollback(status);  
  30.             return createFailResult(baseParam, RetEnum.RET_DB_FAIL);  
  31.         }  

在第10行的代码,未结束事务而直接返回,是造成这个问题的原因.
开发同事之所以不使用spring的事务管理,是因为如果要spring回滚事务,需要抛出异常,而他们还想返回一个业务上的状态值.
比如
return createFailResult(baseParam, RetEnum.RET_METADATA_USER_NOT_EXISTS);

其实我觉得不如使用自定义异常,继承RuntimeException,然后增加一个业务状态的数据成员.

经过这次排查,小有收获,也纠正了自己的一个错误认识。
原来一直以为 mysql
start transaction 是 set autocommit=false 的同义词.
但是两种方式,还有差别.

  1. set autocommit=false;  
  2. update t set str=‘edmond’ where id=1;  
  3. — start transaction会提交之前的事务  
  4. start transaction

但是set autocommit=false不会提交之前的事务.

选中删除本行 本列

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
.box{
width:500px;
height:500px;
}
.shan-box{
width:500px;
height:150px;
background:#666;
}
.shan-box:nth-child(odd){
background:#ccc;
}
</style>
</head>

<body>
<div class="box">
<input type="button" value="删除" class="delete"/>
<div class="shan-box">
<input type="checkbox" />
</div>
<div class="shan-box">
<input type="checkbox" />
</div>
<div class="shan-box">
<input type="checkbox" />
</div>
<div class="shan-box">
<input type="checkbox" />
</div>

</div>
</body>
<script type="text/javascript" src="花枪B端静态页/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
var obj_checked=$(".shan-box input:checked");
var obj_shan=$(".shan-box input:checked").parent(".shan-box");
if(obj_checked.length > 0){
obj_shan.remove();
}else{

}    

})
})
</script>
</html>

 

Weex 环境搭建(win7)

安装 Node.js

  1. node.js需要4.0+
  2. 百度云下载地址http://pan.baidu.com/s/1o84g6c6
  3. 官网下载地址https://nodejs.org/en/
  4. 安装教程请看这里node.js安装图解

安装 weex-toolkit

安装好node.js后,打开CMD工具现在安装weex-toolkit,这是weex的集成环境。

npm install -g weex-toolkit

Weex 环境搭建(win7)

有了weex-toolkit就可以使用weex命令了

我使用的版本是如图,这个可能变化的很快
Weex 环境搭建(win7)

先看一下weex命令
Weex 环境搭建(win7)

Usage: weex foo/bar/we_file_or_dir_path  [options]
Usage: weex debug [options] [we_file|bundles_dir]
Usage: weex init
 
Options:
  --qr          display QR code for PlaygroundApp                      [boolean]
 
  --smallqr     display small-scale version of QR code for PlaygroundApp,try it
                if you use default font in CLI                         [boolean]
 
  -o, --output  transform weex we file to JS Bundle, output path must specified
                (single JS bundle file or dir)
                [for create sub cmd]it specified we file output path
                                                 [default: "no JSBundle output"]
 
  --watch       using with -o , watch input path , auto run transform if change
                happen
  -s, --server  start a http file server, weex .we file will be transforme to JS
 
                bundle on the server , specify local root path using the option
                                                                        [string]
 
  --port        http listening port number ,default is 8081        [default: -1]
 
  --wsport      websocket listening port number ,default is 8082   [default: -1]
 
  --np          do not open preview browser automatic                  [boolean]
 
  -f, --force   [for create sub cmd]force to replace exsisting file(s) [boolean]
 
  -h, --host                                              [default: "127.0.0.1"]
 
 
weex debug -h for Weex debug help information.
 
for cmd example & more information please visit
https://www.npmjs.com/package/weex-toolkit

如果你只是想调试某个we文件,那么执行weex xxx.we即可以运行在本地浏览器中,当然如果执行

weex test.we --qr -h

–qr 即是显示本地地址文件的二维码,安装playground后既可以扫描二维码看到we文件的页面。
-h 是热更新,当然只对浏览器有效

初始化项目hello weex

先建立一个app文件夹,我是这个目录D:/webxm/nodejs/weex-test

然后使用cmd进入weex-text这个目录,或者在这个目录直接打开cmd(按住shift键同时点击鼠标右键选择【在此处打开命令窗口】)

执行如下命令

Weex 环境搭建(win7)

按下回车键出现如下信息

file: .gitignore created.
file: README.md created.
file: index.html created.
file: package.json created.
file: src/main.we created.
file: webpack.config.js created.

接着安装依赖

npm install

现在我们创建了一个目录,然后并且在这里初始化了一个weex-test项目。

目录结构图

Weex 环境搭建(win7)

src-代码目录
index-浏览器启动页面
webpack.config.js-webpack的配置文件
观察package.json里面有这样四个命令

{
  "name": "weex-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "dev": "webpack --watch",
    "serve": "serve -p 8080",
    "test": "echo /"Error: no test specified/" && exit 1"
  },

改成如下(8080端口可以随便改)

{
"name": "weex-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"dev": "webpack & serve -p 8080",
"test": "echo /"Error: no test specified/" && exit 1"
},

现在试试启动这个项目

npm run dev

Weex 环境搭建(win7)
现在浏览器访问一下localhost:8080会出现如下界面

Weex 环境搭建(win7)

好了,现在我们已经启动起来了这个项目。

另一种启动方式

先进入src工作目录,运行对应的we文件,命令如下

weex xxx.we

我运行的文件是这个

Weex 环境搭建(win7)

你系统默认浏览器的窗口将自动打开并且显示Hello Weex!

传送门:weex 真机调试二维码