多线程连接数据库的连接池类:
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中,怎么用多线程控制数据库更新等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)