SQLite事务与自增深度分析
SQLite什么都好,就怕“database is locked”这些年来想尽办法去规避它。
测试代码:
static void Test2()
{
XCode.Setting.Current.TransactionDebug = true; XTrace.WriteLine(Role.Meta.Count + "");
XTrace.WriteLine(Log.Meta.Count + "");
Console.Clear(); Task.Run(() => TestTask());
Thread.Sleep();
Task.Run(() => TestTask());
} static void TestTask(Int32 tid)
{
try
{
XTrace.WriteLine("TestTask {0} Start", tid);
using (var tran = Role.Meta.CreateTrans())
{
var role = new Role();
role.Name = "R" + DateTime.Now.Millisecond;
role.Save();
XTrace.WriteLine("role.ID={0}", role.ID); Thread.Sleep(); role = new Role();
role.Name = "R" + DateTime.Now.Millisecond;
role.Save();
XTrace.WriteLine("role.ID={0}", role.ID); Thread.Sleep(); if (tid == ) tran.Commit();
}
}
catch (Exception ex)
{
XTrace.WriteException(ex);
}
finally
{
XTrace.WriteLine("TestTask {0} End", tid);
}
}
预热环境以后,我们开了两个任务去执行测试函数,间隔1秒。
测试函数负责插入两行数据,间隔3秒。
第一个任务最后会回滚,第二个任务提交。
显然,两个任务会重叠。
比较好奇,任务1申请得到自增1后,任务2申请得到的自增会是多少?
任务1回滚以后,它所申请得到的自增数字如何处理?
结果:
02:45:03.470 6 Y 5 TestTask 1 Start
02:45:03.470 6 Y 5 Transaction.Begin ReadCommitted
02:45:03.486 6 Y 5 Select Count(*) From Role Where Name='R470'
02:45:03.501 6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R470', 0, '');Select last_insert_rowid() newid
02:45:03.517 6 Y 5 开始初始化实体类UserX
02:45:03.517 6 Y 5 完成初始化实体类UserX
02:45:03.533 6 Y 5 role.ID=11
02:45:04.486 14 Y 6 TestTask 2 Start
02:45:04.486 14 Y 6 Transaction.Begin ReadCommitted
02:45:04.486 14 Y 6 Select Count(*) From Role Where Name='R486'
02:45:04.486 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid
02:45:05.251 15 Y 7 Transaction.Begin ReadCommitted
02:45:05.251 15 Y 7 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid
02:45:06.548 6 Y 5 Select Count(*) From Role Where Name='R548'
02:45:06.548 6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R548', 0, '');Select last_insert_rowid() newid
02:45:06.548 6 Y 5 role.ID=12
02:45:09.555 6 Y 5 Transaction.Rollback ReadCommitted
02:45:09.555 6 Y 5 TestTask 1 End
02:45:09.618 14 Y 6 SQL耗时较长,建议优化 5,120毫秒 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid
02:45:09.618 14 Y 6 role.ID=11
02:45:12.633 14 Y 6 Select Count(*) From Role Where Name='R633'
02:45:12.633 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R633', 0, '');Select last_insert_rowid() newid
02:45:12.633 14 Y 6 role.ID=12
02:45:15.649 14 Y 6 Transaction.Commit ReadCommitted
02:45:15.649 14 Y 6 TestTask 2 End
02:45:15.774 15 Y 7 SQL耗时较长,建议优化 10,519毫秒 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid
02:45:15.774 15 Y 7 Transaction.Commit ReadCommitted
02:45:16.622 16 Y 9 Transaction.Begin ReadCommitted
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:06', 'ID=12,Name=R548');Select last_insert_rowid() newid
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:09', 'ID=11,Name=R486');Select last_insert_rowid() newid
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:12', 'ID=12,Name=R633');Select last_insert_rowid() newid
02:45:16.637 16 Y 9 Transaction.Commit ReadCommitted
从测试结果来看:
1,任务1申请得到11和12,任务2也是
2,任务1申请得到11后,任务2启动,执行到Insert时阻塞了5.12秒,直到任务1回滚了事务
3,线程15和16是异步写日志,显然它们也被阻塞,线程15阻塞10.519秒,知道任务2提交事务
结论:SQLite执行更新事务操作时使用排它锁,强制自增数字同步分配!
参考:
http://sqlite.1065341.n5.nabble.com/Transactions-and-sqlite3-last-insert-rowid-td8905.html
> If I understand it correctly, connection C1 can do an INSERT, get
> ROWID 4, C2 does an INSERT, gets 5, and commits, and then C1 commits,
> with its 4; if C1 rolled back, there's no 4 in the database, just 5
> and whatever else, correct?
>
No, this can't happen. As soon as C1 does its insert, it acquires an
exclusive lock on the database. C2 can't do an insert until C1 either
commits or rolls back and releases the lock. If C1 committed, then C2
will get 5, if C1 rolled back, then C2 will get 4.
SQLite事务与自增深度分析的更多相关文章
- C# SQLite事务操作方法分析
本文实例讲述了C# SQLite事务操作方法.分享给大家供大家参考,具体如下: 在 C#中执行Sqlite数据库事务有两种方式:SQL代码和C#代码 1. SQL代码: BEGIN… COMMIT / ...
- const与readonly深度分析(.NET)
前言 很多.NET的初学者对const和readonly的使用很模糊,本文就const和readonly做一下深度分析,包括: 1. const数据类型的优势 2. const数据类型的劣势 3. r ...
- 转:[gevent源码分析] 深度分析gevent运行流程
[gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行 ...
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)
写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...
- AndroidService 深度分析(2)
AndroidService 深度分析(2) 上一篇文章我们Service的生命周期进行了測试及总结. 这篇文章我们介绍下绑定执行的Service的实现. 绑定执行的Service可能是仅为本应用提供 ...
- 深度分析如何在Hadoop中控制Map的数量
深度分析如何在Hadoop中控制Map的数量 guibin.beijing@gmail.com 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数 ...
- MapReduce深度分析(二)
MapReduce深度分析(二) 五.JobTracker分析 JobTracker是hadoop的重要的后台守护进程之一,主要的功能是管理任务调度.管理TaskTracker.监控作业执行.运行作业 ...
- MapReduce深度分析(一)
MapReduce深度分析(一) 一.数据流向分析 图为MapReduce数据流向示意图 步骤1.输入文件从HDFS流向到Mapper节点.在一般情况下,存储数据的节点就是Mapper运行的节点,不需 ...
- 【JVM】深度分析Java的ClassLoader机制(源码级别)
原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...
随机推荐
- 详解Office Add-in 清单文件
作者:陈希章 发表于2017年12月8日 前言 我们都知道,一个Office Add-in,最主要是由两个部分组成的:清单文件(manifest)和真正要用来执行的网站. 清单文件其实是一个标准的XM ...
- 用maven建立java web项目
1.在eclipse的菜单栏选择File->New->Other->Maven->Maven ,并在第一个框打勾,然后点击下一步 2.转换为java的Dynamic Web P ...
- 工作随笔——selenium支持post请求,支持自定义header
背景: 最近在写一个小程序,发现博主所在的地区访问该网站时有防ddos功能验证导致程序不能正常工作. 经过试验发现可以用国外代理ip解决这个问题,但是程序走代理访问延迟高且不稳定. 思路: selen ...
- Sphinx学习笔记(一)
最近负责一个项目,需要用到全文检索,我的环境大体如下: 1.数据保存在MySQL中 2.需要支持中文检索 3.尽可能的简单 选择了Sphinx,至于solr和E ...
- 【python】函数参数关键字索引、参数指定默认值、搜集参数
- IOS学习2——Xcode快捷键大全
转载自:图文解释XCode常用快捷键的使用 刚开始用Xcode是不是发现以前熟悉的开发环境的快捷键都不能用了?怎么快捷运行,停止,编辑等等.都不一样了.快速的掌握这些快捷键,能提供开发的效率. 其实快 ...
- C语言应用程序的内存图
1.综述 c语言应用程序加载到内存,这时它所占据的内存分为四个区,分别为栈Stack,堆Heap,静态存储区Static Area,代码存储区Code Area,这四个区分别放置应用程序的不同部分,从 ...
- discuz管理员登录进入后台管理马上跳转到登录界面
昨天尝试了一下这个discuz论坛,感觉还可以.今天刚刚用管理员账户进入后台管理,准备改一改界面熟悉一下,过不了10秒钟.老是马上就退出来了.我想起来了,昨天是在阿里云服务器上面直接登录这个管理员账号 ...
- Cat 跨线程之 TaggedTransaction 用法和原理分析
代码 package com.dianping.cat.message.internal; import com.dianping.cat.Cat; import com.dianping.cat.m ...
- Web API系列之三 基本功能实现
Web API系列之二讲解了如何搭建一个WebApi的基架,本文主要在其基础之上实现基本的功能.下面开始逐步操作: 一.配置WebApi的路由-用于配置外部如何访问内部资源的url的规则 1.添加Gl ...