Commish13 Ответов: 1

Sql открывает соединение только один раз для нескольких читателей


Я создал веб-сайт на языке C# asp.net. Я часто использую ООП в своем коде. Из-за этого в каждом методе есть читатель. База данных открывается несколько раз, и она работает нормально, но я знаю, что должен быть более эффективный способ сделать это. Для этого поста я показываю только 1 из своих методов, чтобы все было просто.

О чем я спрашиваю? Не мог бы кто-нибудь показать мне, как открыть базу данных один раз и использовать соединение несколькими способами.

Взгляните на мой LoadSchedule() в моей загрузке страницы. Затем в моем методе LoadSchedule я должен открыть базу данных для ее работы.

Должен же быть лучший способ сделать это, верно?

Заранее спасибо.

Что я уже пробовал:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;

public partial class PickAllPool : System.Web.UI.Page
{


    protected void Page_Load(object sender, EventArgs e)
    {
        SqlConnection conn;
        SqlCommand comm;
        SqlDataReader reader;
        string connectionString = ConfigurationManager.ConnectionStrings["Name of connection string"].ConnectionString;
        conn = new SqlConnection(connectionString);
        comm = new SqlCommand("GetSchedule_v2", conn);
        comm.CommandType = CommandType.StoredProcedure;
        try
        {
            conn.Open();
            reader = comm.ExecuteReader();
            if (reader.Read())
            {
                DateTime localDate = DateTime.Now.AddHours(2);
                DateTime PoolStatusActive = Convert.ToDateTime(reader["PoolActive"]);
                DateTime PoolStatusDisabled = Convert.ToDateTime(reader["PoolDisabled"]);

                if (localDate > PoolStatusActive && localDate < PoolStatusDisabled)
                {
                    if (!IsPostBack)
                    {
                       
                        reader.Close();
                        LoadSchedule();                       
                    }

                }

                else
                {
                    poolStatus.Visible = false;
                    timerMsg.Visible = true;
                }
            }

        }

        catch (Exception ex)
        {

            System.Windows.Forms.MessageBox.Show("Database error message: " + ex.Message +
                            "<br>" + ex.Source +
                            "<br>" + ex.TargetSite +
                            "<br>" + ex.StackTrace);
        }
        finally
        {
            // comm.Dispose();
            conn.Close();
        }
    }


    protected void LoadSchedule()
    {
        SqlConnection conn;
        SqlCommand comm;
        SqlDataReader reader;
        string connectionString = ConfigurationManager.ConnectionStrings["PhillyPickAllConnection"].ConnectionString;
        conn = new SqlConnection(connectionString);
        comm = new SqlCommand("GetSchedule_v2", conn);
        comm.CommandType = CommandType.StoredProcedure;

        try
        {
            conn.Open();
            reader = comm.ExecuteReader();
            myRepeater.DataSource = reader;
            myRepeater.DataBind();
            reader.Read();


            reader.Close();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("Database error message: " + ex.Message +
                            "<br>" + ex.Source +
                            "<br>" + ex.TargetSite +
                            "<br>" + ex.StackTrace);
        }
        finally
        {
            comm.Dispose();
            conn.Close();
        }
    }
}

1 Ответов

Рейтинг:
2

OriginalGriff

У тебя гораздо большие проблемы, чем ты думаешь.
Использование

if (!IsPostBack)
и
protected void Page_Load(object sender, EventArgs e)
говорит "это веб - сайт" - и это означает, что ваш код не будет работать в производстве.

Код C# выполняется на сервере, но никогда не выполняется на клиенте - только код Javascript выполняется на клиенте. Поэтому, когда вы используете MessageBox, он показывает диалоговое окно на сервере, а не на клиенте, где пользователь не может его видеть. Это означает, что выполнение кода на сервере остановится и будет ждать, пока пользователь за несколько тысяч миль от него нажмет кнопку "ОК", которую он не видит и даже не знает о ее существовании. Он не получит никакого сообщения об ошибке; все, что он получает, - это замороженный веб-сайт...

Он работает в разработке, потому что сервер и клиент - это одна и та же физическая машина, поэтому, когда сервер показывает диалоговое окно, вы видите его на сервере, и он выглядит так, как будто он работает. Но это не так, не совсем так - и как только вы доберетесь до производства, оно катастрофически провалится.

И учитывая, что это веб - сайт, вы даже не должны пытаться "поделиться" SqlConnection - вы должны создавать его заново каждый раз, когда используете его, потому что они являются скудными ресурсами, и если вы создадите один и держите его, он может длиться слишком долго-даже если клиент выключил свою машину и ушел домой! Учитывая, что веб-сайты предназначены для просмотра несколькими пользователями, это может довольно быстро исчерпать запас подключений к SQL, и тогда пользователи получат сообщения "не удается подключиться к серверу". Или будет, если ваш код не использует MessageBoxes для их отображения ... :вздох:

"Правильный" способ доступа к БД:
using (SqlConnection con = new SqlConnection(strConnect))
    {
    con.Open();
    using (SqlDataAdapter da = new SqlDataAdapter("SELECT MyColumn1, MyColumn2 FROM myTable WHERE mySearchColumn = @SEARCH", con))
        {
        da.SelectCommand.Parameters.AddWithValue("@SEARCH", myTextBox.Text);
        DataTable dt = new DataTable();
        da.Fill(dt);
        myDataGridView.DataSource = dt;
        }
    }
Или
using (SqlConnection con = new SqlConnection(strConnect))
    {
    con.Open();
    using (SqlCommand cmd = new SqlCommand("SELECT MyColumn1, MyColumn2 FROM myTable WHERE mySearchColumn = @SEARCH", con))
        {
        cmd.Parameters.AddWithValue("@SEARCH", myTextBox.Text);
        using (SqlDataReader reader = cmd.ExecuteReader())
            {
            while (reader.Read())
                {
                int id = (int) reader["Id"];
                string desc = (string) reader["description"];
                ...
                }
            }
        }
    }
То using блок гарантирует, что объекты будут утилизированы автоматически, независимо от того, что произойдет.


Commish13

Спасибо за ваш ответ. Просто интересно, Хорошая ли это практика-использовать попытку, поймать?

OriginalGriff

Зависит от того, что вы собираетесь делать с уловом: если вы регистрируете его, сообщаете о нем пользователю или аналогичным образом обрабатываете его, то да. Если вы проглотите его, пройдете мимо, сядете или проигнорируете, то нет.

Но вы можете использовать try...catch с использованием блоков, а также. Однако если вы оставите блок using, соответствующее удаление произойдет автоматически.

Commish13

Привет, я пытаюсь использовать ваш код, но сталкиваюсь с другой проблемой. Всякий раз, когда я помещаю свой ретранслятор в Оператор if, он не заполняет myRepeater. Мне нужно, чтобы оператор if отображал пул в определенную дату и время, а не отображался после определенной даты и времени. Всякий раз, когда я отлаживаю свой код, он проходит через все проблемы, но не отображает мой пул на веб-странице. Просто чтобы вы знали, что дата и время настроены хорошо, так что он будет отображать пул.


частный недействительными LoadSchedule()
{
строка connString = ConfigurationManager.Соединительные нити["
Подключение к базе данных"].Параметр connectionString;
используя (sqlconnection с соед = новый объект sqlconnection(connString))
{
Коннектикут.Открыть();
используя (sqlcommand, который комми = новая команда sqlcommand("GetSchedule_v2", соед))
{
использование (SqlDataReader reader = comm.Метода executereader())
{
в то время как (читатель.читать())
{
LocalDate датавремя = Датавремя.Сейчас; ;
DateTime PoolStatusActive = Конвертировать.ToDateTime(reader["PoolActive"]);
DateTime PoolStatusDisabled = Конвертировать.ToDateTime(reader["PoolDisabled"]);

if (localDate > PoolStatusActive && localDate < PoolStatusDisabled)
{
мой повторитель.Источник данных = считыватель;
мой повторитель.Привязку();
читатель.Читать();

}
}
}
}
}

Есть какие-нибудь предложения, что я должен сделать или изменить?

Спасибо

OriginalGriff

Потому что вы делаете две вещи неправильно:
1) Вы используете Read дважды: один раз в операторе "while" и один раз в операторе "if". Второй заставит его выбросить запись сразу же после того, как все они пройдут тест if.
2) вы устанавливаете считыватель в качестве источника данных для вашего ретранслятора, но это будет обработано только после выхода функции - к этому времени вы прочитаете все строки из считывателя, и там ничего не будет отображаться. Поскольку считыватели не могут быть перемотаны, повторитель по понятным причинам пуст. Создайте коллекцию данных, которую вы хотите, и установите ее в качестве источника данных после завершения цикла.

Commish13

Я просто хочу поблагодарить вас за помощь, но не могли бы вы дать мне пример кода? Я пытаюсь следовать вашему комментарию выше, но независимо от того, что я пытаюсь, это не работает.

OriginalGriff

Что именно вы пытались сделать? Покажите нам код и объясните, что означает "это не работает"!

Commish13

Я вроде как не понимаю, когда вы говорите: "создайте коллекцию данных, которую вы хотите, и установите ее в качестве источника данных после завершения цикла", потому что я могу заставить каждую часть моего кода работать отдельно, но не вместе.

частный недействительными LoadSchedule()
{
строка connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].Параметр connectionString;
используя (sqlconnection с соед = новый объект sqlconnection(connString))
{
Коннектикут.Открыть();
используя (sqlcommand, который комми = новая команда sqlcommand("GetSchedule_v2", соед))
{
использование (SqlDataReader reader = comm.Метода executereader())
{

в то время как (читатель.читать())
{
DateTime localDate = DateTime.Now.AddHours(2);
DateTime PoolStatusActive = Конвертировать.ToDateTime(reader["PoolActive"]);
DateTime PoolStatusDisabled = Конвертировать.ToDateTime(reader["PoolDisabled"]);

if (localDate > PoolStatusActive && localDate < PoolStatusDisabled)
{
Ящик для сообщений.Шоу("Хорошо");
}

еще
{
Ящик для сообщений.Шоу("Плохо");
}
}
}
}
}
}

или

частный недействительными LoadSchedule()
{
строка connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].Параметр connectionString;
используя (sqlconnection с соед = новый объект sqlconnection(connString))
{
Коннектикут.Открыть();
используя (sqlcommand, который комми = новая команда sqlcommand("GetSchedule_v2", соед))
{
использование (SqlDataReader reader = comm.Метода executereader())
{

мой повторитель.Источник данных = считыватель;
мой повторитель.Привязку();
}
}
}
}

OriginalGriff

Ты ведь знаешь, ЧТО ТАКОЕ коллекция, не так ли? А вы знаете, как добавлять объекты в коллекцию?