2013-06-26 153 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;--,那麼你的整個用戶數據庫就會消失。如果你想要一個(非常健康的)解決方案,請查看存儲過程。