首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >我有任何SQL泄漏吗?

我有任何SQL泄漏吗?
EN

Code Review用户
提问于 2014-03-04 20:37:20
回答 2查看 417关注 0票数 5

这是一个Windows服务,将在大约600台机器上运行。它用于跟踪用户连接到的作业服务器(通过某种负载均衡器,而不是我的区域)。我将此信息存储在SQL表中,并希望确保没有任何SQL泄漏。

它从用户计算机(用户名/网络名称/AD名称)中获取信息,并从Load (指向一个作业服务器,所有这些服务器在检索的XML节点中都有不同的值)请求一个简单的XML,然后将这些信息发送到存储过程,该存储过程更新或将信息插入到表中,如果应用程序未打开,则不会发生这些情况。

代码语言:javascript
代码运行次数:0
运行
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.Data.Sql;
using System.Xml.Linq;
using System.Diagnostics;
using System.Data.SqlClient;
using System.Data.ProviderBase;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Management;
using System.Net;
using System.Threading;

namespace AppServerTracker
{
    class Tracker
    {
        int intConnCount;
        string strServer;
        string strUserName;
        Process[] process = Process.GetProcessesByName("MShell");
        public static string strInput = "http://Website.for.load.Balancer.com";

        string strErrorMSG = "No Error"; //will show that there has been no error in the table.

        private static string SQLConnectionString = Properties.Resources.ConnStage;
        public SqlConnection SQLConnection = new SqlConnection(SQLConnectionString);

        public Tracker()
        {

        }

        public void Main()
        {
            if (process.Length > 0)
            {
                intConnCount = process.Length;

                ManagementScope ms = new ManagementScope("\\\\.\\root\\cimv2");
                ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_ComputerSystem");
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, query);
                foreach (ManagementObject mo in searcher.Get())
                {
                    strUserName = mo["UserName"].ToString();
                }
                // Remove the domain part from the username
                string[] usernameParts = strUserName.Split('\\');
                // The username is contained in the last string portion.
                strUserName = usernameParts[usernameParts.Length - 1];

                string strComputerName = Environment.MachineName;

                if (isValid(strInput))
                {
                    try
                    {
                        XmlReader xmlReader = XmlReader.Create(strInput);
                        using (xmlReader)
                        {
                            while (xmlReader.Read())
                            {
                                if (xmlReader.NodeType == XmlNodeType.Text)
                                {
                                    strServer = xmlReader.Value.ToString();
                                    strServer = strServer.Replace("\r", "");
                                    strServer = strServer.Replace("\n", "");
                                    strServer = strServer.Replace(" ", "");
                                }
                            }
                            xmlReader.Close();
                        }
                    }
                    catch (Exception e)
                    {
                        strServer = "Error";
                        strErrorMSG = "Error with the xmlReader Exception as follows: " + e.ToString();
                    }
                    finally
                    {
                    }
                }
                else
                {
                    strServer = "XML-Missing";
                }

                try
                {
                    using (SQLConnection)
                    {
                        SQLConnection.Open();
                        using (SqlCommand TrackSproc = new SqlCommand("spServerTracking", SQLConnection))
                        {
                            TrackSproc.CommandType = System.Data.CommandType.StoredProcedure;
                            TrackSproc.Parameters.AddWithValue("@UserName", strUserName);
                            TrackSproc.Parameters.AddWithValue("@Server", strServer);
                            TrackSproc.Parameters.AddWithValue("@ConnCount", intConnCount);
                            TrackSproc.Parameters.AddWithValue("@MachineName", strComputerName);
                            TrackSproc.Parameters.AddWithValue("@Error", strErrorMSG);
                            TrackSproc.ExecuteNonQuery();
                        }
                    }
                }
                catch (Exception e)
                {
                    // E-mail Exception 
                }
                finally
                {
                    SQLConnection.Close();
                }
            }
        }

        public bool isValid(string url)
        {
            HttpWebRequest urlReq;
            HttpWebResponse urlRes;
            try
            {
                urlReq = (HttpWebRequest)WebRequest.Create(url);
                urlReq.Method = "HEAD";
                urlReq.Timeout = 100000;
                urlRes = (HttpWebResponse)urlReq.GetResponse();
                urlRes.Close();
                return true;
            }
            catch (Exception ex)
            {
                //Url not valid
                strErrorMSG = "Exception From isValid Method. Exception to follow: " + ex.ToString();
                return false;
            }

        }
    }
}

下面是这个类的全部代码。

  • 我假设我使用的一些语句是无关的。
  • 假设已经做了注释,我应该将连接移动到using语句,而不是使它在其他地方可访问,因为它是不需要的
  • 我删除了一些无关的评论(在这篇文章中的一些评论中提到过)
  • 我在这里有一个恼人的命名方案,我知道,这是我从学校学到的坏习惯。当我做完这篇评论后,我会把这个问题纠正过来,命名是很难的。
EN

回答 2

Code Review用户

回答已采纳

发布于 2014-03-04 22:27:29

你的代码不对称..。

您在using块中打开您的SQLConnection,但在最后一个块中将它关闭.总之,关闭是完全多余的。

如果SqlConnection超出了范围,它就不会关闭。因此,必须通过调用close或Dispose显式关闭连接。关闭和处理在功能上是等价的。

您已经在try块内处理连接(作为using的一部分),所以这一切都是毫无意义的。

SQLConnection ..。它是如何被创造出来的?你让它神奇地出现在using的序言里.需要..。更多..。信息。

为什么要在块中注释掉旧代码。如果您不再使用sqlCommand变量(因为它移动到外部使用块),那么请关闭它,不要注释掉该行。

如果不了解存储过程的更多功能,就很难确定是否还有其他问题,但是,您的代码看起来可能很简单(尽管当程序退出using块时,SQLConnection将被释放。这是一个不对称的情况..。连接在块启动时是打开的,我们不会返回它):

代码语言:javascript
代码运行次数:0
运行
复制
try
{
    using (SQLConnection)
    {
        SQLConnection.Open();
        using (SqlCommand TrackSproc = new SqlCommand("spServerTracking", SQLConnection))
        {
            TrackSproc.CommandType = System.Data.CommandType.StoredProcedure;
            TrackSproc.Parameters.AddWithValue("@UserName", strUserName);
            TrackSproc.Parameters.AddWithValue("@Server", strServer);
            TrackSproc.Parameters.AddWithValue("@ConnCount", intConnCount);
            TrackSproc.Parameters.AddWithValue("@MachineName", strComputerName);
            TrackSproc.Parameters.AddWithValue("@Error", strErrorMSG);
            TrackSproc.ExecuteNonQuery();
        }
    }
}
catch (Exception e)
{
    // E-mail Exception 
}
票数 6
EN

Code Review用户

发布于 2014-03-05 22:44:17

还不清楚您的SqlConnection是否被重用:如果客户机代码(它使用跟踪器)实例化跟踪器实例,然后多次调用Tracker.Main,那么它将被重用。

在处置完毕后,海事组织不应再使用任何物体。例如,MSDN建议类内有一个布尔值,以确保只释放一次。如果这个(合法的)模式是在SqlConnection类中实现的,那么它将不会正确地释放在释放之后重新获得的对象(如果您重用的话)。

在实践中,SqlConnection在被处理后可能被安全地重用;但是,在理论上,这是未定义的行为。用于SqlConnection.Dispose的MSDN说,

使用完组件后调用Dispose。Dispose方法使组件处于不可用的状态。调用Dispose之后,必须释放对组件的所有引用,这样垃圾收集器才能回收组件占用的内存。有关更多信息,请参见清理非托管资源和实现Dispose方法。

如果您的SQLConnection对象是局部变量,则会更安全:

代码语言:javascript
代码运行次数:0
运行
复制
using (SqlConnection sqlConnection = new SqlConnection(SQLConnectionString)) { ... }

如果希望保持SQLConnection作为跟踪器的实例成员,跟踪器实现IDisposable和从Tracker.Dispose调用SQLConnection.Dispose将是惯用的做法。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/43439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档