string str = Request["str"];
DBFactory.DeleteWhen("delete from pjy_favorite where ID IN(" + str + ")", DBFactory.DefaultDB);
WriteJSON(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里直接调用数据层的方法去操作数据库。
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;
}
}
}
}
用这个去更新数据会出现并发吗?
呵呵.测试代码而已.何况设计模式不是你想的样式.
@[秦时明月]: 会出现数据不同步错误(代码执行正常但是数据异常)。比如原来的表有3列[a,b,c],甲和乙同时打开了编辑页面,甲修改了b的值,乙修改了c的值,甲先点了保存,乙后点的。这个时候只有乙的修改是有效的,甲的修改被覆盖掉了。正确的情况应该是甲保存成功,乙保存失败,提示乙重新加载数据。比较简单的解决并发更新的方法看这里:http://msdn.microsoft.com/zh-cn/library/ms182776.aspx 或者你换个ORM框架,很多都帮你解决了更新冲突,这套DB层代码写的很一般。
@水牛刀刀:
会出现数据不同步错误(代码执行正常但是数据异常)。比如原来的表有3列[a,b,c],甲和乙同时打开了编辑页面,甲修改了b的值,乙修改了c的值,甲先点了保存,乙后点的。这个时候只有乙的修改是有效的,甲的修改被覆盖掉了。正确的情况应该是甲保存成功,乙保存失败,提示乙重新加载数据。比较简单的解决并发更新的方法看这里:http://msdn.microsoft.com/zh-cn/library/ms182776.aspx 或者你换个ORM框架,很多都帮你解决了更新冲突,这套DB层代码写的很一般。
我是问,我的同时对数据进行修改时,非同一条记录会出现数据乱串的情况否?
@[秦时明月]: 不是同一条记录不会互相影响的
首先,你传入的参数没有校验,何况你还是写操作(删除)你不怕传入恶意参数把你整张表都删了?其次,你说的数据并发问题,你这个只要客户端发起请求,都会对服务器进行操作,我的结论是有可能会引发并发问题。原因如下:
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
如果我实例化了一个对象obj.让它在系统中就一个单例.
然后许多的线程同时访问obj的所有方法,会不会出现数据乱串的情况? (这些所有的方法都不会读取和设置该obj成员变量,可能会读取)
如
@[秦时明月]: 我想你是没有看我给你提供的链接,什么是多线程开发我想你还没弄清楚?你怎么保证“多的线程同时访问obj的所有方法”?不了解内存分配怎么知道程序处理的过程呢?我建议你先把上面的资料仔细看看再说?若考虑并发,就从“客户端请求(负载均衡),数据层加锁控制,进行大数据量压力测试”出发,具体方法谷歌去。
var 单例=new HttpResponse();
多线程中(thread1,thread2.....)
都用这个单例的方法去进行操作,明白吗?
不谈注入。与Asp.net 何干呢? 光光执行一条delete语句扯上什么并发呢, 执行结果无非删除了,没删成,已经删了没得删而已。如果有什么问题带上场景好吗? 不知道(数据发现被相互篡改)是一种什么情况。