[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]多个事务,先更新,再select的测试代码

上一篇:[备忘]理解事务级别,试验的代码
下一篇:[备忘]mysql 存储过程的调试工具

添加日期:2014/11/4 0:32:40 快速返回   返回列表 阅读2164次


import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.impl.NutDao;
import org.nutz.trans.Atom;
import org.nutz.trans.Trans;

import cn.gbase.jiangsu.data.transfer.bean.ShopUser;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

public class TestUpdate {

    NutDao daoOut = new NutDao();
    MysqlDataSource dsOut = null;
    
    TreeMap<Long,String> msgMap = new TreeMap<Long,String>();

    private void setOutDataSource() {
        dsOut = new com.mysql.jdbc.jdbc2.optional.MysqlDataSource();

        // 更新连接信息
        dsOut.setServerName("localhost");
        dsOut.setDatabaseName("shop");
        dsOut.setUser("root");
        dsOut.setPassword("123456");

        // 设置数据源
        daoOut.setDataSource(dsOut);
    }

    private void doWork() throws SQLException, InterruptedException {
        setOutDataSource();

        // 初始为1
        daoOut.update(ShopUser.class, Chain.make("accountBalance", 0), Cnd.where("id", "=", 6));

        msgMap.clear();
        
        // 100个线程加1
        for (int i = 0; i < 10; i++) {
            new Thread() {
                public void run() {
                    updateMoney();
                }
            }.start();
        }
        
        Thread.sleep(10000);
        // ShopUser u = daoOut.fetch(ShopUser.class, 6);
        // System.out.println(u.getAccountBalance());
        
        StringBuilder sb =new StringBuilder();
        for(Entry<Long,String> entry:msgMap.entrySet()){
            sb.append(entry.getKey());
            sb.append(":").append(entry.getValue()).append("\n");
        }
        System.out.println(sb.toString());

    }

    private void updateMoney() {

        // 随机延迟
        try {
            Thread.sleep(new Random().nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // 有事务的话,多个sql执行使用的是同一个connection
        // 无事务的话,不论select还是update,每次都是新开的一个connection
        Trans.exec(Connection.TRANSACTION_READ_UNCOMMITTED, new Atom() {
            public void run() {
                
                // 更新
                daoOut.update(ShopUser.class, Chain.make("accountBalance", BigDecimal.ONE), Cnd.where("id", "=", 6));

                // 随机延迟
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                // 读取
                ShopUser u = daoOut.fetch(ShopUser.class, 6);
                BigDecimal money = u.getAccountBalance();
                echo(""+money,System.nanoTime());
            }
        });

    }

    
    private synchronized void echo(String msg, long time){
        msgMap.put(time, msg);
    }

    public static void main(String[] args) {
        TestUpdate xx = new TestUpdate();
        try {
            try {
                xx.doWork();
            } catch (InterruptedException e) {
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}



想了两个小时才想通~~~

因为一开始执行,控制台就把10个update语句打出来了。
啊?10个更新都执行了?
想了N久也想不通~~
update,铁定上锁,怎么会同时执行呢?
…………
后来,把update后的等待时间改为10秒,终于暴露出来了:
很多Lock wait timeout exceeded,一看行号,就是执行update那行~~

瞬间想通,虽然控制台把update语句打出来了,但不代表它执行完了~~
这些update语句都在那等锁呢。

第一个update语句,上锁(事务里貌似是上的共享锁,即其它事务能查,不能更新),
然后等10秒,查询,commit事务,解锁
然后轮到第二个update语句~

在mysql里用:
show status like 'innodb_row_lock%';
可以看到Innodb_row_lock_current_waits
随着select语句执行,这个waits数就会减一,而之前的10秒不会变,
充分说明了,事务结束才会解锁。

---------------------------
update和select之间,被其它事务update的可能性是0,因为update上锁了,事务结束才会解锁。其它事务只能查询

也就保证了,select到的值,是之前update的值。
 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved