首页 新闻 会员 周边 捐助

关于ASP.NET的一个根本问题

1
悬赏园豆:100 [已关闭问题] 关闭于 2012-03-24 21:34
            string str = Request["str"];
DBFactory.DeleteWhen("delete from pjy_favorite where ID IN(" + str + ")", DBFactory.DefaultDB);
WriteJSON(1);

每个客户端用户同时调用此方法时,会不会出现数据并发问题(数据发现被相互篡改)?

[秦时明月]的主页 [秦时明月] | 小虾三级 | 园豆:738
提问于:2012-03-01 08:51
< >
分享
所有回答(5)
0

会存在。

悟行 | 园豆:12559 (专家六级) | 2012-03-01 09:35

不要信口开河说话.

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-01 09:37

最厌恶信口开河之人.从根源说问题

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-01 09:41

@[秦时明月]: 你不是说:”会不会出现数据并发问题?“。我的意思是:会出现啊。

支持(0) 反对(0) 悟行 | 园豆:12559 (专家六级) | 2012-03-01 09:51
0

没有做多线程是不会改的,多线程情况下,没有设计好就会。

az235 | 园豆:8483 (大侠五级) | 2012-03-01 09:46
1

不管这段代码是你写着玩的还是真实项目的代码,从请求参数里读取id,然后拼接成查询字符串,很明显存在sql注入隐患,建议改用参数查询。接着回答你的问题:这段代码在多线程下不会出现问题,因为你这里执行的是一个delete操作。假设有3个查询同时执行,分别删除ID IN [1,2,3] 和 [2,3,4] 和 [1,5],那么无论什么顺序,最终结果总是ID IN [1,2,3,4,5]的记录被删除了。考虑数据并发冲突更多是在update的情况下。这段代码如在update数据的情况下是否会有并发问题,需要看你的DBFactory里相关方法是如何实现的了。另外,不要在code behind里直接调用数据层的方法去操作数据库。

水牛刀刀 | 园豆:6350 (大侠五级) | 2012-03-01 10:07
public class DBFactory
{
static DBFactory(){
string dbType = ConfigurationManager.AppSettings["dbType"];
string type = "Qin.Orm." + dbType;
string linkString = System.Configuration.ConfigurationManager.AppSettings["linkString"];
Type tp = Type.GetType(type);
object[] constructParms = new object[] { linkString };
DefaultDB= (DB)Activator.CreateInstance(tp, constructParms);
object currentDatabaseType=Enum.Parse(typeof(DatabasesType),dbType);
GlobalData.DatabasesType=(DatabasesType)(currentDatabaseType);
Console.WriteLine(GlobalData.DatabasesType);

}
public static DB DefaultDB;
DefaultDB=new MSSQL(....);
/*
* 由SharpDevelop创建。
* 用户: qinshichuan
* 日期: 2011-12-18
* 时间: 15:38
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Web;

namespace Qin.Orm
{
///<summary>
/// Description of MSSQL.
///</summary>
public class MSSQL:DB
{
public MSSQL(string connectionString)
{
this.ConnectionString = connectionString;
this.DBType= DatabasesType.MSSQL;
}

public override DbCommand GetProcDbCommand(string procName)
{
SqlConnection dbConnection = (SqlConnection) this.GetDbConnection();
SqlCommand command = new SqlCommand();
command.CommandText = procName;
command.CommandType = CommandType.StoredProcedure;
return command;
}
public override List<T> GetPagedListDesc<T>(int startIndex,int endIndex,Field primaryKey,Field onlyMark)
{
string sqlSum="select count(*) from "+primaryKey.TableName+ "where "+WhereChecker.ToSafeString(onlyMark.WhereContent);
long sum=Convert.ToInt64(DBFactory.DefaultDB.GetFirstData(sqlSum));
long end=sum-startIndex+1;
long start=sum-endIndex+1;
string cmdString="select top "+(endIndex-startIndex+1)+" * from (select top "+(end)+
" * from "+primaryKey.TableName+" where "+WhereChecker.ToSafeString(onlyMark.WhereContent)+" order by "+primaryKey.FieldName+" asc) as "+
primaryKey.TableName+" order by "+primaryKey.FieldName+" DESC";



DBFactory.CurrentSql=cmdString;
DbDataReader reader=Qin.Orm.DBFactory.DefaultDB.GetDbDataReader(cmdString);
List<T> list=new List<T>();
while (reader.Read()) {
T data=DynamicBuilder<T>.CreateBuilder(reader).Build(reader);
list.Add(data);

}
reader.Close();
return list;

}
public override List<T> GetWebPagedListDesc<T>(Field primaryKey,Field onlyMark)
{
HttpRequest Request=System.Web.HttpContext.Current.Request;
int p_start=int.Parse(Request.QueryString["p_start"]);
int p_end=int.Parse(Request.QueryString["p_end"]);
return GetPagedListDesc<T>(p_start,p_end,primaryKey,onlyMark);
}

public override object GetFirstData(string cmdString)
{
SqlCommand dbCommand = (SqlCommand) this.GetDbCommand(cmdString);
dbCommand.Connection.Open();
object firstData = dbCommand.ExecuteScalar();
dbCommand.Connection.Close();
return firstData;
}
///<summary>
/// 执行一条sql语句通过参数形式
///</summary>
///<param name="parameters">Dictionary形式的参数列表</param>
///<param name="sql">sql语句</param>
///<param name="startTransaction">是否开启事务</param>
///<param name="type">执行语句的类型 增删改查 1 2 3 4</param>
///<returns>增加则返回增加后的主键值,否则是受影响的函数</returns>
public override object ExecuteSqlByParameters(Dictionary<string,object> parameters,string sql,bool startTransaction,int type){
object newPrimaryKey=null;
if (parameters==null||parameters.Count==0) {
throw new ArgumentException("parameters 参数为空,方法InsertDataByParameters调用出错!");
}
else{
//增加
if (type==1) {
sql+="\r\n "+"select SCOPE_IDENTITY()";
}
SqlCommand procDbCommand = (SqlCommand) this.GetDbCommand(sql);
int index=1;
foreach (KeyValuePair<string,object> parameter in parameters)
{
procDbCommand.Parameters.AddWithValue("@p"+index, parameter.Value);
index++;
}

if (procDbCommand.Connection.State == ConnectionState.Closed)
{
procDbCommand.Connection.Open();
}
if (startTransaction==false) {
newPrimaryKey=procDbCommand.ExecuteScalar();
procDbCommand.Connection.Close();
}
else{
SqlTransaction dbTransaction=procDbCommand.Connection.BeginTransaction();
procDbCommand.Transaction=(SqlTransaction)dbTransaction;
try {
newPrimaryKey=procDbCommand.ExecuteScalar();
dbTransaction.Commit();

} catch (InvalidOperationException) {
dbTransaction.Rollback();
throw new InvalidOperationException("InvalidOperationException ExecuteInsertSqlByParameters");
}
finally{
procDbCommand.Connection.Close();

}
}
return newPrimaryKey;
}
}
public override DbDataReader GetDbDataReader(string cmdString)
{
SqlCommand dbCommand = (SqlCommand) this.GetDbCommand(cmdString);
dbCommand.Connection.Open();
return dbCommand.ExecuteReader(CommandBehavior.CloseConnection);
}

public override DbConnection GetDbConnection()
{
return new SqlConnection(this.ConnectionString);
}

public override DbCommand GetDbCommand(string cmdString)
{
return new SqlCommand(cmdString, (SqlConnection) this.GetDbConnection());
}

public override DataView GetDataView(string cmdString, string RowFilter, string Sort, DataViewRowState RowState)
{
return new DataView(this.GetDataTable(cmdString), RowFilter, Sort, RowState);
}

public override DataTable GetDataTable(string cmdString)
{
return this.GetDataSet(cmdString).Tables[0];
}

public override DataSet GetDataSet(string cmdString)
{
SqlCommand dbCommand = (SqlCommand) this.GetDbCommand(cmdString);
dbCommand.Connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(dbCommand);
DataSet dataSet = new DataSet();
adapter.Fill(dataSet);
dbCommand.Connection.Close();
return dataSet;
}

public override int ExecuteProc(string procName, Queue<SuperSqlParameter> superSqlParameters)
{
if (superSqlParameters.Count <= 0)
{
throw new Exception("SuperSqlParameter里面的参数为零");
}
SqlCommand procDbCommand = (SqlCommand) this.GetProcDbCommand(procName);
int num = -1;
foreach (SuperSqlParameter parameter in superSqlParameters)
{
procDbCommand.Parameters.Add(procName, (SqlDbType) parameter.ParameterDbType, parameter.Size);
}
if (procDbCommand.Connection.State == ConnectionState.Closed)
{
procDbCommand.Connection.Open();
}
num = procDbCommand.ExecuteNonQuery();
procDbCommand.Connection.Close();
return num;
}

public override int ExecuteOneSql(string cmdString)
{
SqlCommand dbCommand = (SqlCommand) this.GetDbCommand(cmdString);
dbCommand.Connection.Open();
int num = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
return num;
}
private string _connetionString;
public override string ConnectionString {
get {
return _connetionString;
}
set {
_connetionString=value;
}
}
}
}


用这个去更新数据会出现并发吗?

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-01 10:10

呵呵.测试代码而已.何况设计模式不是你想的样式.

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-01 10:21

@[秦时明月]: 会出现数据不同步错误(代码执行正常但是数据异常)。比如原来的表有3列[a,b,c],甲和乙同时打开了编辑页面,甲修改了b的值,乙修改了c的值,甲先点了保存,乙后点的。这个时候只有乙的修改是有效的,甲的修改被覆盖掉了。正确的情况应该是甲保存成功,乙保存失败,提示乙重新加载数据。比较简单的解决并发更新的方法看这里:http://msdn.microsoft.com/zh-cn/library/ms182776.aspx 或者你换个ORM框架,很多都帮你解决了更新冲突,这套DB层代码写的很一般。

支持(0) 反对(0) 水牛刀刀 | 园豆:6350 (大侠五级) | 2012-03-01 10:26

@水牛刀刀:

会出现数据不同步错误(代码执行正常但是数据异常)。比如原来的表有3列[a,b,c],甲和乙同时打开了编辑页面,甲修改了b的值,乙修改了c的值,甲先点了保存,乙后点的。这个时候只有乙的修改是有效的,甲的修改被覆盖掉了。正确的情况应该是甲保存成功,乙保存失败,提示乙重新加载数据。比较简单的解决并发更新的方法看这里:http://msdn.microsoft.com/zh-cn/library/ms182776.aspx 或者你换个ORM框架,很多都帮你解决了更新冲突,这套DB层代码写的很一般。

我是问,我的同时对数据进行修改时,非同一条记录会出现数据乱串的情况否?

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-02 08:45

@[秦时明月]: 不是同一条记录不会互相影响的

支持(0) 反对(0) 水牛刀刀 | 园豆:6350 (大侠五级) | 2012-03-02 18:45
0

首先,你传入的参数没有校验,何况你还是写操作(删除)你不怕传入恶意参数把你整张表都删了?其次,你说的数据并发问题,你这个只要客户端发起请求,都会对服务器进行操作,我的结论是有可能会引发并发问题。原因如下:

1.IIS是多线程的,每个URL请求都会启一个线程。

2.并发问题关于三方面,一是一定时间内客户端请求量,二是你系统数据层的架构设计(比如有没有用Lock),三测试,系统有没有经过大数据量的压力测试,没有实践任务人都不能给你肯定答案。

最后说一下你贴的代码,参数没有用校验处理有安全总理 ,其次你用的DBFactory是自己写的还是三方类库看下实现细节是否安全。

参考资料:

1.http://msdn.microsoft.com/zh-cn/library/c5kehkcz(VS.80).aspx

2.http://kb.cnblogs.com/a/2310420/

3.http://msdn.microsoft.com/zh-cn/library/bb470252.aspx

4.http://kb.cnblogs.com/a/1534382/

5.http://www.cnblogs.com/leslies2/archive/2012/02/07/2310495.html

lonely_rain | 园豆:752 (小虾三级) | 2012-03-01 12:05

如果我实例化了一个对象obj.让它在系统中就一个单例.

然后许多的线程同时访问obj的所有方法,会不会出现数据乱串的情况? (这些所有的方法都不会读取和设置该obj成员变量,可能会读取)

 

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-02 08:49

@[秦时明月]: 我想你是没有看我给你提供的链接,什么是多线程开发我想你还没弄清楚?你怎么保证“多的线程同时访问obj的所有方法”?不了解内存分配怎么知道程序处理的过程呢?我建议你先把上面的资料仔细看看再说?若考虑并发,就从“客户端请求(负载均衡),数据层加锁控制,进行大数据量压力测试”出发,具体方法谷歌去。

支持(0) 反对(0) lonely_rain | 园豆:752 (小虾三级) | 2012-03-02 09:10

var 单例=new  HttpResponse();

多线程中(thread1,thread2.....)

都用这个单例的方法去进行操作,明白吗?

支持(0) 反对(0) [秦时明月] | 园豆:738 (小虾三级) | 2012-03-03 08:34
0

不谈注入。与Asp.net 何干呢? 光光执行一条delete语句扯上什么并发呢, 执行结果无非删除了,没删成,已经删了没得删而已。如果有什么问题带上场景好吗? 不知道(数据发现被相互篡改)是一种什么情况。

ChatinCode | 园豆:2272 (老鸟四级) | 2012-03-05 10:51
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册