问题描述:sqlite3数据放置在某一台电脑的某个共享文件夹下,操作数据库的应用程序安装在同一局域网下的很多台电脑上,由于存在多人同时使用该应用程序,所以存在多人同时操作数据库的情况。经过测试发现,最常见的情况是当两人或者多人往数据库中写入数据时,只有其中一个写入成功,其他数据都写入失败。

解决方案分析:

由于本人编写程序未MFC应用程序,所以尝试使用windows互斥量mutex,具体的使用方法如下:

bool CMFCApplication2Dlg::Lock()

{

  m_pMutex = CreateMutex(NULL, false, L"txt_mutex");

  if (NULL == m_pMutex)

  {

    return false;

  }

  DWORD nRet = WaitForSingleObject(m_pMutex, INFINITE);

  if (nRet != WAIT_OBJECT_0)

  {

    return false;

  }

  return true;

}

bool CMFCApplication2Dlg::UnLock()

{

  return ReleaseMutex(&m_pMutex);

}

在某用户开始进行写入操作时,先调用Lock()获取mutxt,写入完成之后调用UnLock()释放mutxt。然并卵,该方法并不奏效。(可能由于本人对windows多线程/多进程编程这一块太过生疏,所以无法利用这方面的知识来解决这个问题,如果有大神知道解决方法,求不吝赐教)

所以经过一番思考之后,决定使用在共享盘的那台电脑上跑一个服务端小程序来防止数据库的操作冲突。

具体实现方法如下:

思路分析:在服务端每收到一个客户端的连接请求之后,都创建一个新的线程来处理相应的操作,新的线程不断的去获取客户端发来的消息,当客户端发来的消息是”开始操作”时,线程将尝试获取互斥量mutxt,获取成功之后将给客户端发送回复消息,当该线程接收到”操作结束”的消息时,线程将释放互斥量mutxt,并且会断开该客户端与服务端的socket连接。

服务端代码:

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
using namespace std; static HANDLE m_mutex = INVALID_HANDLE_VALUE; DWORD WINAPI AnswerThread(LPVOID lparam)
{
SOCKET ClientSocket = (SOCKET)(LPVOID)lparam;
int bytesRecv;
while ()
{
bytesRecv = SOCKET_ERROR;
char sendbuff[] = "ok";
char recvbuf[] = "";
for (int i = ; i<(int)strlen(recvbuf); i++)
{
recvbuf[i] = '\0';
}
while (bytesRecv == SOCKET_ERROR)
{
bytesRecv = recv(ClientSocket, recvbuf, sizeof(recvbuf), );
}
string recved = recvbuf;
if (recved == "op_begin")
{
WaitForSingleObject(m_mutex, INFINITE);
cout << "op_begin" << endl;
send(ClientSocket, sendbuff, sizeof(sendbuff), );
}
if (recved == "op_end")
{
cout << "op_end" << endl;
ReleaseMutex(&m_mutex);
closesocket(ClientSocket);
return ;
}
}
return ;
}
int main()
{
WSADATA wsaData;
int iRet = WSAStartup(MAKEWORD(, ), &wsaData);
if (iRet != NO_ERROR)
printf("Error at WSAStartup()\n"); SOCKET m_socket;
m_socket = socket(AF_INET, SOCK_STREAM, );
if (m_socket == INVALID_SOCKET)
{
printf("Error at socket():%ld\n", WSAGetLastError());
WSACleanup();
return ;
}
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
service.sin_port = htons(); if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("bind() failed.\n");
closesocket(m_socket);
return ;
}
else
printf("bind ok.\n"); if (listen(m_socket, ) == SOCKET_ERROR)
printf("Error listening on socket.\n");
else
printf("listening ok.\n"); SOCKET AcceptSocket;
printf("waiting for a client to connect...\n");
m_mutex = CreateMutex(NULL, FALSE, L"Mutex");
if (!m_mutex)
{
cout << "Failed to CreateMutex !" << endl;
return ;
}
int count = ;
while ()
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(m_socket, NULL, NULL);
}
count++;
printf("client num %d connected.\n", count); DWORD dwThreadId;
HANDLE hThread; hThread = CreateThread(NULL, NULL, AnswerThread, (LPVOID)AcceptSocket, , &dwThreadId);
if (hThread == NULL)
{
printf("CreatThread AnswerThread() failed.\n");
}
else
{
printf("create thread %d ok.\n", count);
}
CloseHandle(hThread);
}
closesocket(m_socket);
WSACleanup();
}

客户端代码:(进入数据库操作前)

WSADATA wsaData;

if (WSAStartup(MAKEWORD(, ), &wsaData) != )

{

  TRACE("Failed to load Winsock");

  return;

}

string txtPath = save_path + "\\ip.txt";

ifstream infile(txtPath);

string ip;

getline(infile, ip);

infile.close();

SOCKADDR_IN addrSrv;

addrSrv.sin_family = AF_INET;

addrSrv.sin_port = htons();

addrSrv.sin_addr.S_un.S_addr = inet_addr(ip.c_str());

sockClient = socket(AF_INET, SOCK_STREAM, );

if (SOCKET_ERROR == sockClient){

  TRACE("Socket() error:%d", WSAGetLastError());

  return;

}

if (connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET){

  TRACE("Connect failed:%d", WSAGetLastError());

  return;

}

char buff[] = "op_begin";

send(sockClient, buff, sizeof(buff), );

int bytesRecv = SOCKET_ERROR;

char recvbuf[] = "";

for (int i = ; i<(int)strlen(recvbuf); i++)

{

  recvbuf[i] = '\0';

}

while (bytesRecv == SOCKET_ERROR)

{

  CMessageDlg message;

  message.DoModal();

  bytesRecv = recv(sockClient, recvbuf, sizeof(recvbuf), );

}

客户端代码:(数据库操作完成之后)

char buff[] = "op_end";

send(sockClient, buff, sizeof(buff), );

closesocket(sockClient);

注:由于经验不足,本方法可能有很多内存释放,资源利用等细节没有考虑到,所以本方法仅供参考。另外有关socket编程部分的代码参考:

http://blog.csdn.net/chence19871/article/details/44019633

多人操作sqlite3数据库冲突问题解决方法的更多相关文章

  1. 使用 SQLiteManager 操作 sqlite3 数据库

    SQLiteManager https://github.com/misato/SQLiteManager4iOS 本人以前从事过嵌入式开发,后来转职为iOS开发,即使如此,也绝不想去碰C语言级别的面 ...

  2. 《Python操作SQLite3数据库》快速上手教程

    为什么使用SQLite数据库? 对于非常简单的应用而言,使用文件作为持久化存储通常就足够了,但是大多数复杂的数据驱动的应用需要全功能的关系型数据库.SQLite的目标则是介于两者之间的中小系统.它有以 ...

  3. (一一三)使用系统自带框架操作SQLite3数据库

    系统自带的框架是基于C语言的,使用比较繁琐. 下面是使用步骤: 首先导入libsqlite3.0.dylib. ①在Document目录下打开数据库,如果没有则创建. NSString *sqlite ...

  4. .net操作Oracle数据库步骤及方法

    1.首先安装PL/SQL Developer Oracle客户端软件 2.安装Oracle Instant Client(即时客户端) 安装与配置 配置环境变量ORAClE HOME 地址为insta ...

  5. 安装mysql数据库及问题解决方法

    1.mysql官网下载安装包,官网地址:www.mysql.com [root@seiang software]# ll total 580020 -rw-r--r--. 1 root root 59 ...

  6. sqlite3 not found问题解决方法

    测试发现,有些Android手机自带sqlite3命令,有些不带.对于不带sqlite3的手机,我们可以手动将sqlite3加入系统. 执行如下命令 adb remount adb push 路径/s ...

  7. jQuery$命名冲突问题解决方法

    也许你在看此文章之前还不知道jquery有一个noConflict()东西了,它就是为了避免与其它js插件碰到相同变量的一个解决方法,利用noConflict()可以把变量存到其它指定的变量中去如,我 ...

  8. pip2和pip3冲突问题解决方法

    python使用pip安装模块时报错:unable to create process using ' '的解决方法: 参考:http://qoogle.cn/?id=39 1.删除C:\Python ...

  9. Flask:操作SQLite3(0.1)

    Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2 本文介绍了第一次在Flask框架中操作SQLite3数据库的测试,参考了官网的文档Using SQLite 3 wit ...

随机推荐

  1. SVN 忽略文件但不删除文件

    SVN忽略一些不必要的文件但不删除 如果svn仓库中有一些不希望被别人提交的文件 该如何忽略掉对这个文件的更改但又不删除这个文件呢? 在找了一堆解决方案后得出了如下结论 去除要被忽略文件的版本控制 基 ...

  2. C#按回车Enter使输入焦点自动跳到下一个TextBox的方法收集

    在录入界面中,用户往往需要按回车键时光标自动跳入下一个文本框,以方便录入操作.在C#中实现该功能有多种方法,以下是小编收集的不使用TAB键,而直接用回车键将光标转到下一个文本框的实现方法. 一.利用W ...

  3. 「C语言」文件的概念与简单数据流的读写函数

    写完「C语言」单链表/双向链表的建立/遍历/插入/删除 后,如何将内存中的链表信息及时的保存到文件中,又能够及时的从文件中读取出来进行处理,便需要用到”文件“的相关知识点进行文件的输入.输出. 其实, ...

  4. 改变mvc web api 支持android ,ios ,ajax等方式跨域调用

    公司一个移动后端的项目用到了 webapi 项目搭建到外网环境共app开发者调用测试接口时遇到了一个问题 接口不允许跨域调用 .查阅资料明白 同源策略原则根据请求报头值 Origin 与回应报头值 A ...

  5. 推荐几个的chorme的扩展程序

    下面来解释下这几个插件 (0)Context : 管理这些乱七八糟的扩展程序,插件用的时候,点开,不用的时候,关闭,这样可以降低游览器的负荷 (1)AngularJS Batarang : 测试ang ...

  6. 操作iframe

    iframe是在页面中嵌套的子页,当前页面(这里称为父页)和嵌套页面(这里称为子页)可以相互控制: 当父页控制子页用contentWindow,用法为 对象.contentWindow.documen ...

  7. Vue条件渲染

    gitHub地址:https://github.com/lily1010/vue_learn/tree/master/lesson08 一 v-if显示单个元素 注意else只能跟在v-if或者v-s ...

  8. Windows Azure 上传 VM

    One of the great features of Windows Azure is VHD mobility. Simply put it means you can upload and d ...

  9. linux服务器如何设置目录权限,让开发只能在测试目录下开发,不在线上目录上开发

    当一台服务器上,既有测试环境,也有生成的环境,开发需要在线上测试,如果开发生产环境的权限,那开发容易误操作 需求如下: (1)生产环境的代码,必须有专用的账号登陆进行管理 (2)开发测试环境的代码,开 ...

  10. 【转】self.myOutlet=nil、viewDidUnload、dealloc的本质剖析

    对于iphone开发人员来说,内存管理是极为重要的技巧,哪怕程序的功能再强大,设计再漂亮,如果内存控制不好,也难逃程序莫名退出的噩运,这与网页开发是完全不同的. 内存控制里面有很多门道,在这里分析一下 ...