多线程 连接数据库,C#多线程写数据库

多线程 连接数据库,C#多线程写数据库,第1张

线程连接数据库的连接池类:

public static class ConnectionPool

{

private static object locker = new object();

private static Dictionary<string, SqlConnection> Connections = null;

public static SqlConnection GetConnection<T>() where T : class, new()

{

string databaseName = NACommonExtensionsGetDatabaseName<T>();

if (stringIsNullOrEmpty(databaseName))

return null;

if (Connections == null)

{

lock (locker)

{

Connections = new Dictionary<string, SqlConnection>();

}

}

string connKey = FindFreeSqlConnection(databaseName);

if (connKey != null)

return Connections[connKey];

else

{

string strconn = NACommonExtensionsGetConnectionString<T>();

int poolSize = NACommonExtensionsGetConnectionPoolSize<T>();

lock (locker)

{

for (int i = 0; i < poolSize; ++i)

{

SqlConnection conn = new SqlConnection(strconn);

connOpen();

ConnectionsAdd(databaseName + "_" + iToString(), conn);

connClose();

}

}

return Connections[FindFreeSqlConnection(databaseName)];

}

}

private static string FindFreeSqlConnection(string databaseName)

{

IEnumerable<string> connKeys = ConnectionsKeysWhere(item => itemStartsWith(databaseName));

if (connKeys != null && connKeysCount() > 0)

{

foreach (string key in connKeys)

{

if (Connections[key]State == ConnectionStateClosed)

return key;

}

}

return null;

}

}

附加上其中用到的三个方法:

internal static int GetConnectionPoolSize<T>() where T : class, new()

{

string database = GetDatabaseName<T>();

string[] poolSizeArray = ConfigurationManagerAppSettings["ConnectionsPoolSize"]Split('|');

if (poolSizeArray != null)

{

foreach (string sizeItem in poolSizeArray)

{

string[] sizeItemArray = sizeItemSplit(':');

if (database == sizeItemArray[0])

return intParse(sizeItemArray[1]);

}

}

return 50;

}

public static string GetConnectionString<T>() where T : class, new()

{

string tableName = GetTableName<T>();

string[] databaseArray = ConfigurationManagerAppSettings["DatabaseArray"]Split('|');

if (databaseArray != null)

{

foreach (string database in databaseArray)

{

string tableNameList = ConfigurationManagerAppSettings[database];

string[] tables = ConfigurationManagerAppSettings[database]Split('|');

if (tables != null && tablesLength > 0)

if (tablesContains(tableName))

return ConfigurationManagerConnectionStrings[database]ConnectionString;

}

}

return stringEmpty;

}

public static string GetDatabaseName<T>() where T : class, new()

{

string tableName = GetTableName<T>();

string[] databaseArray = ConfigurationManagerAppSettings["DatabaseArray"]Split('|');

if (databaseArray != null)

{

foreach (string database in databaseArray)

{

string tableNameList = ConfigurationManagerAppSettings[database];

string[] tables = ConfigurationManagerAppSettings[database]Split('|');

if (tables != null && tablesLength > 0)

if (tablesContains(tableName))

return database;

}

}

return stringEmpty;

}

你的提问就有问题

当你的程序不管是不是多线程

获得到一个数据库连接是 数据库会把这个连接标记为繁忙 当其他程序访问时它会返回另外空闲的连接

连接个数是有限的 如果一直不释放连接 数据库就会告诉你连接已经使用完了

这里和线程安全有何关系呢? 线程安全和数据库 *** 作没有直接关系

其实你要实现的这个功能,根本不需要用多线程。原因,你要去修改一条数据,那么你肯定要有两个数据,1:哪条数据,2:当前是不是正在被修改中。那么你要获取这两个量的话,你必须要起一条线程起来不停地去检查这个到底现在是什么状态,是可以修改的状态才运行你当前要修改的这一 *** 作。

建议这样实现:再你要检查的那个表中加一个标志性字段,可以定义成bit,1的时候表示当前这一条数据可以被修改,也就是没有其他人来 *** 作它,0的时候,这条数据不能被修改,其他人正在 *** 作它。当遇到不能修改这条数据的时候,这里可以用多线程控制去做每隔一小段时间的重复查询,看看这条数据是否可以修改了。

//将数据库中的数据条数分段

public void division(){

//获取要导入的总的数据条数

String sql3="SELECT count() FROM [CMD][dbo][mycopy1]";

try {

pss=consprepareStatement(sql3);

rss=pssexecuteQuery();

while(rssnext()){

Systemoutprintln("总记录条数:"+rssgetInt(1));

sum=rssgetInt(1);

}

//每30000条记录作为一个分割点

if(sum>=30000){

n=sum/30000;

residue=sum%30000;

}else{

residue=sum;

}

Systemoutprintln(n+" "+residue);

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

}

线程类

public MyThread(int start,int end) {

thisend=end;

thisstart=start;

Systemoutprintln("处理掉余数");

try {

Systemoutprintln("--------"+ThreadcurrentThread()getName()+"------------");

ClassforName(SQLSERVERDRIVER);

Systemoutprintln("加载sqlserver驱动");

cons = DriverManagergetConnection(CONTENTS,UNS,UPS);

stas = conscreateStatement();

Systemoutprintln("连接SQLServer数据库成功!!");

Systemoutprintln("加载mysql驱动");

ClassforName(MYSQLDRIVER);

con = DriverManagergetConnection(CONTENT,UN,UP);

sta = concreateStatement();

// 关闭事务自动提交

consetAutoCommit(false);

Systemoutprintln("连接mysql数据库成功!!");

} catch (Exception e) {

eprintStackTrace();

}

// TODO Auto-generated constructor stub

}

public ArrayList<Member> getAll(){

Member member;

String sql1="select from (select row_number() over (order by pmcode) as rowNum," +

" from [CMD][dbo][mycopy1]) as t where rowNum between "+start+" and "+end;

try {

Systemoutprintln("正在获取数据");

allmembers=new ArrayList();

rss=stasexecuteQuery(sql1);

while(rssnext()){

member=new Member();

membersetAddress1(rssgetString("address1"));

membersetBnpoints(rssgetString("bnpoints"));

membersetDbno(rssgetString("dbno"));

membersetExpiry(rssgetString("expiry"));

membersetHispoints(rssgetString("hispoints"));

membersetKypoints(rssgetString("kypoints"));

membersetLevels(rssgetString("levels"));

membersetNames(rssgetString("names"));

membersetPmcode(rssgetString("pmcode"));

membersetRemark(rssgetString("remark"));

membersetSex(rssgetString("sex"));

membersetTelephone(rssgetString("telephone"));

membersetWxno(rssgetString("wxno"));

membersetPmdate(rssgetString("pmdate"));

allmembersadd(member);

// Systemoutprintln(membergetNames());

}

Systemoutprintln("成功获取sqlserver数据库数据!");

return allmembers;

} catch (SQLException e) {

// TODO Auto-generated catch block

Systemoutprintln("获取sqlserver数据库数据发送异常!");

eprintStackTrace();

}

try {

rssclose();

stasclose();

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

return null;

}

public void inputAll(ArrayList<Member> allmembers){

Systemoutprintln("开始向mysql中写入");

String sql2="insert into testmycopy2 values (,,,,,,,,,,,,,)";

try {

ps=conprepareStatement(sql2);

Systemoutprintln("-------------------------等待写入数据条数: "+allmemberssize());

for(int i=0;i<allmemberssize();i++){

pssetString(1, allmembersget(i)getPmcode());

pssetString(2, allmembersget(i)getNames());

//Systemoutprintln(allmembersget(i)getNames());

pssetString(3, allmembersget(i)getSex());

pssetString(4, allmembersget(i)getTelephone());

pssetString(5, allmembersget(i)getAddress1());

pssetString(6, allmembersget(i)getPmdate());

pssetString(7, allmembersget(i)getExpiry());

pssetString(8, allmembersget(i)getLevels());

pssetString(9, allmembersget(i)getDbno());

pssetString(10, allmembersget(i)getHispoints());

pssetString(11, allmembersget(i)getBnpoints());

pssetString(12, allmembersget(i)getKypoints());

pssetString(13, allmembersget(i)getWxno());

pssetString(14, allmembersget(i)getRemark());

//插入命令列表

//psaddBatch();

psexecuteUpdate();

}

//psexecuteBatch();

concommit();

psclose();

conclose();

thisflag=false;

Systemoutprintln(ThreadcurrentThread()getName()+"--->OK");

} catch (SQLException e) {

// TODO Auto-generated catch block

Systemoutprintln("向mysql中更新数据时发生异常!");

eprintStackTrace();

}

}

@Override

public void run() {

// TODO Auto-generated method stub

while(true&&flag){

thisinputAll(getAll());

}

}

首先对数据库(尤其是Access)使用多线程大多不会提高效率(除非SQL中有耗时但不好资源的 *** 作,如T-SQL中休眠之类的语句)。

建议楼主:使用队列,将要执行的SQL语句放入队列中(如:SystemCollectionQueue或ArrayList),然后用一根线程一条一条执行,另外Access不支持事物回滚只有自己想办法实现了。滥用多线程会加大程序开发的难度,以及包括程序的不稳定。

另外:cbyvft的答案“……所有的线程使用同一个连接”

,是严重错误的!!连接对象Connection不能迸发,也就是不能多根线程共享一个连接对象,否则很容易引发异常(报错为:基础对象与RAW分离之类的信息)。

若非要用多线程来做,我可以给你一段代码(我以前开发的项目中一部分),请加我的“百度Hi”并发消息给我,我传给你。

我不在这里帖代码了,因为实现的代码较多,而且比较复杂(使用多线程要考虑很多问题,代码要硕壮通用,所以代码量较大)。

设置connautocommit(false)

这样就不会存在自动提交 也就是说 你的 *** 作还只是内存 *** 作 别人看到的只能是没有变化的表 直到你循环完毕用conncommit()

增加线程缓存大小

连接管理器线程处理服务器监听的网络接口上的客户端连接请求。连接管理器线程将每个客户端连接与专用于它的线程关联,该线程负责处理该连接的身份验证和所有请求处理。因此,线程和当前连接的客户端之间是一对一的比例。确保线程缓存足够大以容纳所有传入请求是非常重要的。

MySQL提供了许多与连接线程相关的服务器变量:

线程缓存大小由thread_cache_size系统变量决定。默认值为0(无缓存),这将导致为每个新连接设置一个线程,并在连接终止时需要处理该线程。如果希望服务器每秒接收数百个连接请求,那么应该将thread_cache_size设置的足够高,以便大多数新连接可以使用缓存线程。可以在服务器启动或运行时设置max_connections的值。

还应该监视缓存中的线程数(Threads_cached)以及创建了多少个线程,因为无法从缓存中获取线程(Threads_created)。关于后者,如果Threads_created继续以每分钟多于几个线程的增加,请考虑增加thread_cache_size的值。

使用MySQL show status命令显示MySQL的变量和状态信息。这里有几个例子:

Monyog线程缓存监测

Monyog提供了一个监控线程缓存的屏幕,名为“线程”。与MySQL线程相关的服务器变量映射到以下Monyog指标:

Monyog线程屏幕还包括“线程缓存命中率”指标。这是一个提示线程缓存命中率的指标。如果值较低,则应该考虑增加线程缓存。在状态栏以百分比形式显示该值;它的值越接近100%越好。

如果这些指标的值等于或超过指定值,则可以将每一个指标配置为发出警告和/或严重警报

以上就是关于多线程 连接数据库,C#多线程写数据库全部的内容,包括:多线程 连接数据库,C#多线程写数据库、JAVA多线程访问数据库如何实现线程安全、.NET中,怎么用多线程控制数据库更新等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9512785.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存