2013-06-26 155 views
0

我目前有一个小应用程序向服务器发送了很多不同的MySQL查询。我的想法是将连接,查询和读取仅包含实际查询作为参数。关闭MySQL连接功能

这里是我的了:

public static MySqlDataReader mySqlRead(string cmdText) 
    { 

     string connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";"; 

     MySqlConnection conn = new MySqlConnection(connString); 
     MySqlCommand command = conn.CreateCommand(); 

     command.CommandText = cmdText; 

     try 
     { 
      conn.Open(); 
      MySqlDataReader reader = command.ExecuteReader(); 
      return reader; 
     } 

     catch (MySqlException) 
     { 
      throw; 
     } 

    } 

我连接,并在此发送查询:

private void btnLogin_Click(object sender, EventArgs e) 
    { 
     string username = txtLogin.Text; 
     string password = ORFunc.GetMD5Hash(txtPassword.Text); 

     MySqlDataReader orRead = ORFunc.mySqlRead("SELECT * FROM orUsers WHERE username = '" + username + "' AND pass = '" + password + "'"); 
     while (orRead.Read()) 
     { 
      MessageBox.Show(orRead["id"].ToString()); 
     } 
    } 

作品就像一个魅力......但是,你可以在上面看到,连接从未关闭。当我在.ExecuteReader()后面添加conn.Close()时,读者是空的,返回后的所有内容当然是无用的。

也许这是一个愚蠢的问题,但我相当新的C#所以请慷慨,任何暗示赞赏。

欢呼声,

PRIMUS

回答

1

您遇到困难是因为您的想法与连接到.NET Framework中的数据库的程序预期的模式相反。
通常情况下,在该模式中,你有一个方法

INITIALIZE/OPEN/USE/CLOSE/DESTROY 

的ADO。NET对象连接到提取或更新数据所需的工作

此外,您的代码有一个称为Sql Injection(see this famous explanation)的严重问题,因为当您连接字符串以形成命令文本时,您无法防御恶意用户尝试攻击你的数据库

private void btnLogin_Click(object sender, EventArgs e) 
{ 
    string username = txtLogin.Text; 
    string password = ORFunc.GetMD5Hash(txtPassword.Text); 

    MySqlParameter p1 = new MySqlParameter("@uname", username); 
    MySqlParameter p2 = new MySqlParameter("@pass", pass); 
    string cmdText = "SELECT * FROM orUsers WHERE username = @uname AND pass = @pass" 
    DataTable dt = ORFunc.GetTable(cmdText, p1, p2); 
    foreach(DataRow r in dt.Rows) 
    { 
     Console.WriteLine(r["ID"].ToString()); 
    } 
} 

public static DataTable GetTable(string cmdText, params MySqlParameter[] prms) 
{ 
    string connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";"; 
    // This is the INITIALIZE part 
    using(MySqlConnection conn = new MySqlConnection(connString)) 
    using(MySqlCommand command = new MySqlCommand(cmdText, conn)) 
    { 
     // OPEN 
     conn.Open(); 
     DataTable dt = new DataTable(); 
     command.Parameters.AddRange(prms); 

     // USE 
     MySqlDataReader reader = command.ExecuteReader(); 
     dt.Load(reader); 
     return dt; 
    } // The closing brace of the using statement is the CLOSE/DESTROY part of the pattern 
} 

当然,这是一个通用的例子,在我的实际工作中,我不经常使用这些通用的方法,喜欢写需要返回到上层的基本对象专门的数据访问代码的代码

+0

伟大的,理解和使用...还要感谢罗素! – PrimuS

2

最近我在JAVA类似的问题,但我认为同样会为你工作。从本质上讲,你可以创建一个表示“SqlCall”对象(或其他)的类。这个类将有可访问的成员,包括连接和结果。该类的ctor将采取您的查询文本。然后,你所要做的就是创建该类的一个新实例,在该类的一个方法中运行该查询(它将设置和/或返回结果),获取结果,然后当你完成后,在你的类上调用close()(然后它必须被编码,以便关闭内部保持的连接)。从技术上讲,更好的方法是扩展连接类本身,但由于您是C#的新手,因此我不会详细讨论这样做。

在我写下面的代码时,我意识到我可能没有真正回答你的问题。但是,有一个在现在打了退堂鼓,因此在这里没有一点是我有:

public class SqlCall { 

    private static connString = "server=" + ORVars.sqlServerAddr + ";port=" + ORVars.sqlServerPort + ";uid=" + ORVars.sqlServerUID + ";pwd=" + ORVars.sqlServerPass + ";database=" + ORVars.sqlServerDB + ";"; 
    private MySqlConnection conn; 
    private MySqlCommand command; 
    private MySqlDataReader reader; 

    public SqlCall(String query) { 

     conn = new MySqlConnection(connString); 
     command = conn.CreateCommand(); 
     command.CommandText = query; 

    } 

    public MySqlDataReader execute() throws Exception { 
     conn.Open(); 
     reader = command.ExecuteReader(); 
     return reader; 
    } 

    public void close() { 
     reader.close(); 
     conn.close(); 
    } 

} 

您的登录密码是:

private void btnLogin_Click(object sender, EventArgs e) { 
    string username = txtLogin.Text; 
    string password = ORFunc.GetMD5Hash(txtPassword.Text); 

    SqlCall sqlcall = new SqlCall("SELECT * FROM orUsers WHERE username = '" + username + "' AND pass = '" + password + "'"); 

    try { 
     MySqlDataReader orRead = sqlcall.execute(); 
     while (orRead.Read()) 
     { 
      MessageBox.Show(orRead["id"].ToString()); 
     } 
     sqlcall.close(); 
    } catch (Exception ex) { 
     // dostuff 
    } 
} 

的一点是,除非你将数据复制到在一个新的DataTable一开始,你必须保持连接畅通。

在另一个注释中,您的代码是通向SQL注入的。不知道那是什么?举个例子:如果我说我的用户名是';DROP TABLE orUsers;--,那么你的整个用户数据库就会消失。如果你想要一个(非常健康的)解决方案,请查看存储过程。