Форум программистов, компьютерный форум, киберфорум
C++ Builder: Базы данных
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/15: Рейтинг темы: голосов - 15, средняя оценка - 4.60
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
1

C++ Builder, mySQL и транзакции

10.12.2016, 11:05. Показов 3091. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день!

Подскажите неопытному...

Есть база на mySQL. Есть приложение на C++ Builder.
Подключаюсь к базе через ADOConnection.
Хочу создать транзакцию на добавление данных одновременно в 2 таблицы.
Через средства ADO все норм.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
try{      
      //Запускается транзакция
      dmMain->ADOC_Base->BeginTrans();
      //Выполняем запрос
    //.....
      }
 
      //Подтверждение сделанных изменений
      dmMain->ADOC_Base->CommitTrans();
 
   }//end try
 
   //Обработка ошибок
   catch(Exception &e){
 
      //Откат транзакции (сделанных изменений)
      dmMain->ADOC_Base->RollbackTrans();
 
      //Строка сообщения для MessageBox
      AnsiString asMessage = "Ошибка сохранения. Описание: " + e.Message;
      //Вывод сообщения об ошибке
      Application->MessageBox(asMessage.c_str(), "Ошибка", MB_ICONERROR);
 
   }  //End catch(Exception &e)
Но хочу работать с базой напрямую.
Пишу запрос напрямую в mysql:
SQL
1
2
3
4
5
6
7
8
9
START TRANSACTION;
 
INSERT INTO Catalog_Brand(Brand, Country)
VALUES VALUES ('123', 'Russia');
 
INSERT INTO Catalog_BrandGroup(Id_Brand, Id_Group)
VALUES VALUES ('1', '1');
 
COMMIT;
Все работает.

А если через ADOQuery тот же запрос, то программа ругается, что ошибка во второй строке. т.е. транзакцию через ADOQuery провести не могу. Как правильно это сделать? Через какой компонент или может как исправить запрос?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.12.2016, 11:05
Ответы с готовыми решениями:

Не устанавливается MySQL ODBC Driver. Как работать на C++ Builder с MySQL ?
Windows XP. Устанавливаю mysql-connector-odbc-noinstall-5.2.6-win32 Вместо обычной...

Транзакции и mysql
Привет всем. Возник вопрос следующего плана. К примеру есть функция в программе, которая делает...

Транзакции MySql
есть код считающий кол-во остатков, проблема при обращении с нескольких клиентов не учитывается...

php+MySQL транзакции
Доброго времени суток! Есть такая задача: Создайте приложение (PHP + MySQL), которое позволяет...

23
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 12:32 2
Доброго, потому что ADOQuery пенсионер, и не научен интуитивно исключать ошибки запроса, которые Вы в него передаете, к примеру такие как два раза указано VALUES VALUES.
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 13:30  [ТС] 3
Там ошибка, торопился, набил два раза. Но в остальном не понятно. Объясните пожалуйста как это можно реализовать?

Должно быть так:
SQL
1
2
3
4
5
6
7
8
9
START TRANSACTION;
 
INSERT INTO Catalog_Brand(Brand, Country)
VALUES ('123', 'Russia');
 
INSERT INTO Catalog_BrandGroup(Id_Brand, Id_Group)
VALUES ('1', '1');
 
COMMIT;
Вопрос остается открытым
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 13:47 4
Ну а покажите как в коде вы прописываете этот запрос
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 14:10  [ТС] 5
Вообще вот так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
   try{
      //Проверка ввода наименования производителя. Если оно пустое или
      //содержит только пробелы, то вывести сообщение об ошибке
      if(DBEditEh_Brand->Text.Trim().IsEmpty())
         throw 1;
 
      //Проверка ввода Происхождения. Если оно пустое
      //вывести сообщение об ошибке
      if(DBComboBoxEh_ProductBirth->Text.Trim().IsEmpty())
         throw 2;
 
      //Проверка ввода Группы. Если оно пустое
      //вывести сообщение об ошибке
      if(DBComboBoxEh_Group->Text.Trim().IsEmpty())
         throw 3;
 
      //Запускается транзакция
      dmMain->ADOC_Base->BeginTrans();
 
      //Сохраняем параметры в отдельные переменные
      AnsiString asBrand = frmBrandData->DBEditEh_Brand->Text;
      AnsiString asCountry = frmBrandData->DBEditEh_Country->Text;
      AnsiString asProductBirth = frmBrandData->DBComboBoxEh_ProductBirth->Text;
      AnsiString asBirthday = frmBrandData->DBEditEh_Birthday->Text;
      AnsiString asDiscriptionShot = frmBrandData->Memo_DiscriptionShot->Text;
      AnsiString asDiscriptionFull = frmBrandData->DBEditEh_DiscriptionFull->Text;
      AnsiString asLogo = frmBrandData->DBEditEh_Logo->Text;
      int iIdGroup;
      if(DBComboBoxEh_Group->ItemIndex != -1){
         iIdGroup = DBComboBoxEh_Group->KeyItems->Strings[DBComboBoxEh_Group->ItemIndex].ToInt();
      }
      else
         throw 3;
 
      //Определяется режим (добавления\редактирования данных)
      //Если нет Id у бренда
      if (frmBrandData->DBEditEh_Id->Text.Trim() == ""){
 
         //Формируется и выполняется запрос на добавление Производителя
         dmCatalog->ADOQ_Brand->Close();
            dmCatalog->ADOQ_Brand->SQL->Clear();
         dmCatalog->ADOQ_Brand->SQL->Add("INSERT INTO Catalog_Brand(Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo)");
            dmCatalog->ADOQ_Brand->SQL->Add("VALUES (:Brand, :Country, :ProductBirth, :Birthday, :DiscriptionShot, :DiscriptionFull, :Logo);");
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Brand")->Value = asBrand;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Country")->Value = asCountry;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("ProductBirth")->Value = asProductBirth;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Birthday")->Value = asBirthday;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("DiscriptionShot")->Value = asDiscriptionShot;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("DiscriptionFull")->Value = asDiscriptionFull;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Logo")->Value = asLogo;
            dmCatalog->ADOQ_Brand->ExecSQL();
 
         //Определяется Id добавленной записи
         frmBrandData->ds_BrandData->DataSet->Active = false;
            frmBrandData->ds_BrandData->DataSet->Active = true;
         frmBrandData->ds_BrandData->DataSet->Locate("Brand", asBrand, TLocateOptions()<<loCaseInsensitive);
            AnsiString asIdBrand = frmBrandData->ds_BrandData->DataSet->FieldByName("Id_Brand")->AsString;
 
         //Добавляется группа для созданного производителя
         dmCatalog->ADOQ_Brand->SQL->Clear();
         dmCatalog->ADOQ_Brand->SQL->Add("INSERT INTO Catalog_BrandGroup(Id_Brand, Id_Group)");
            dmCatalog->ADOQ_Brand->SQL->Add("VALUES (:Id_Brand, :Id_Group);");
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Id_Brand")->Value = asIdBrand;
         dmCatalog->ADOQ_Brand->Parameters->ParamByName("Id_Group")->Value = iIdGroup;
         dmCatalog->ADOQ_Brand->ExecSQL();
 
         //Отображение Id созданного производителя в поле DBEditEh_Id
         DBEditEh_Id->Text = asIdBrand;
      }
 
      //Подтверждение сделанных изменений
      dmMain->ADOC_Base->CommitTrans();
 
   }//end try
 
   //Обработка ошибок
   catch(int i_Error){
 
      //Определение режима заполнения
       switch(i_Error){
           case 1:  //Если не введено Наименование производителя
 
            //Вывод сообщения об ошибке
            Application->MessageBox("Необходимо обязательно указать "
               "Наименование производителя", "Ошибка", MB_ICONERROR);
 
            //Показывается предупреждающая картинка
            frmBrandData->Image_Brand->Visible = true;
 
               break;   //End case 1
 
        case 2:   //Если не выбрано Происхождение
 
            //Вывод сообщения об ошибке
            Application->MessageBox("Необходимо обязательно указать "
            "Происхождение", "Ошибка", MB_ICONERROR);
 
            //Показывается предупреждающая картинка
            frmBrandData->Image_ProductBirth->Visible = true;
 
            break;   //End case 2
 
         case 3:   //Если не выбрана группа
 
            //Вывод сообщения об ошибке
            Application->MessageBox("Необходимо обязательно указать "
            "Группу", "Ошибка", MB_ICONERROR);
 
            //Показывается предупреждающая картинка
            frmBrandData->Image_Group->Visible = true;
            
            break;   //End case 3
 
      }  //End switch(i_Error)
 
   }  //end catch(int i_Error)
 
   //Обработка ошибок
   catch(Exception &e){
 
      //Откат транзакции (сделанных изменений)
      dmMain->ADOC_Base->RollbackTrans();
 
      //Строка сообщения для MessageBox
      AnsiString asMessage = "Ошибка сохранения. Описание: " + e.Message;
 
      //Вывод сообщения об ошибке
      Application->MessageBox(asMessage.c_str(), "Ошибка", MB_ICONERROR);
 
   }  //End catch(Exception &e)
Сейчас транзакцию провожу на стороне программы, но хочу, чтобы в запросе это было. Пробовал в ADOQuery сначала весь запрос составить по вышеуказанной конструкции:
SQL
1
2
3
4
5
6
START TRANSACTION;
INSERT INTO Catalog_Brand(Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo)
VALUES ('123', '', 'Импортный', '', '', '', '');
INSERT INTO Catalog_BrandGroup(Id_Brand, Id_Group)
VALUES ('11', '2');
COMMIT;
Выводил на отдельную кнопку, чтобы только этот запрос выполнился:
C++
1
dmCatalog->ADOQ_Brand->ExecSQL();
. Но выдает ошибку (на скрине)
Миниатюры
C++ Builder, mySQL и транзакции  
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 14:25 6
Нашел, пару тонких моментов, не уверен но все же:

1) Попробуйте запрос сделать одной строкой, и так что бы был пробел между название таблицы и передаваемыми данными (точка с запятой в конце необязательна). Типа так:
SQL
1
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES (:Id_Brand, :Id_Group)
2)
Цитата Сообщение от akrufar Посмотреть сообщение
dmCatalog->ADOQ_Brand->Parameters->ParamByName("Id_Brand")->Value = asIdBrand;
Если передаете значение как параметры, Вы должны передавать их соответсвующим типом. То есть поле в таблице, строка, то и как строку должны передавать, если дата, то как и дату,а не просто Value.
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 14:44  [ТС] 7
Цитата Сообщение от Dinkin Посмотреть сообщение
Нашел, пару тонких моментов, не уверен но все же:
1) Попробуйте запрос сделать одной строкой, и так что бы был пробел между название таблицы и передаваемыми данными (точка с запятой в конце необязательна). Типа так:
SQLВыделить код
1
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES (:Id_Brand, :Id_Group)
Передалал так:
SQL
1
2
3
4
START TRANSACTION
INSERT INTO Catalog_Brand (Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo) VALUES ('123', '', 'Импортный', '', '', '', '')
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES ('11', '2')
COMMIT
Но ошибка все такая же. Не помогло...=(
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 15:04 8
Цитата Сообщение от akrufar Посмотреть сообщение
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES ('11', '2')
А поля как понимаю числовые, а вы их в кавычках шлете
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 15:10  [ТС] 9
Да нет разницы...Ругается-то он на другую строку. К тому же на стороне mySql если делать тот же запрос, все норм. А через программу, через Ado ошибка...
Убрал:
SQL
1
2
3
4
START TRANSACTION
INSERT INTO Catalog_Brand (Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo) VALUES ('123', '', 'Импортный', '', '', '', '')
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES (11, 2)
COMMIT
Ничего не изменилось. Причина в чем-то другом
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 15:25 10
Скрин структуры БД можно?
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 15:28  [ТС] 11
Вот:
Миниатюры
C++ Builder, mySQL и транзакции  
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 15:40 12
Ок, а теперь закоментите
C++
1
dmCatalog->ADOQ_Brand->ExecSQL();
И вместо нее выведите текст запроса dmCatalog->ADOQ_Brand->Text и сюда...при условии что запрос у вас в одну строку.
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 15:50  [ТС] 13
Не понял. Куда вывести?
У меня кнопка. По нажатию на нее выполняется:
C++
1
dmCatalog->ADOQ_Brand->ExecSQL();
Ок, закомментировал.
А запрос куда выводить?
Сам запрос:
SQL
1
2
3
4
START TRANSACTION
INSERT INTO Catalog_Brand (Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo) VALUES ('123', '', 'Импортный', '', '', '', '')
INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES (11, 2)
COMMIT
Располагается в dmCatalog->ADOQ_Brand->SQL. Его туда заранее сохранил. В принципе можно и так:
C++
1
2
3
4
5
6
dmCatalog->ADOQ_NameForCB->Close();
dmCatalog->ADOQ_NameForCB->SQL->Clear();
dmCatalog->ADOQ_Brand->SQL->Add("START TRANSACTION");
dmCatalog->ADOQ_Brand->SQL->Add("INSERT INTO Catalog_Brand (Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo) VALUES ('123', '', 'Импортный', '', '', '', '')");
dmCatalog->ADOQ_Brand->SQL->Add("INSERT INTO Catalog_BrandGroup (Id_Brand, Id_Group) VALUES (11, 2)");
dmCatalog->ADOQ_Brand->SQL->Add("COMMIT");
Выполняем следующей командой:
C++
1
dmCatalog->ADOQ_Brand->ExecSQL();
Так вот при выполнении и появляется ошибка..
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 19:37 14
Вобщем так долго будем гадать, вы можете мне прислать копию базы что у вас есть,я бы у себя протестировал.
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 19:49  [ТС] 15
Да тут не обязательно моя база. Свою не могу, к сожалению (причины есть). А вообще мне бы достаточно любого примера на любой таблице из любой базы. Главное чтобы был пример того, как необходимо сформировать запрос и через какой компонент, чтобы транзакция прошла на стороне сервера, при этом сам запрос формировать необходимо на стороне программы.
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 19:50 16
У вас какая среда?
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
10.12.2016, 19:52  [ТС] 17
С++Builder 6
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
10.12.2016, 20:03 18
Понятно, на С++Builder 6 для связи использовать луче сторонние компоненты. А Запрос у Вас правильно составлен, просто похоже что конфликт с полями БД и посылаемыми данными.
0
91 / 3 / 2
Регистрация: 19.05.2016
Сообщений: 38
11.12.2016, 08:13  [ТС] 19
Так если был бы конфликт с полями или данными, то запрос напрямую через phpmyAdmin тоже выдавал бы ошибку. А там он проходит хорошо. Опять же если отдельно отправлять через ADO запрос на добавление
SQL
1
INSERT INTO Catalog_Brand (Brand, Country, ProductBirth, Birthday, DiscriptionShot, DiscriptionFull, Logo) VALUES ('123', '', 'Импортный', '', '', '', '')
все проходит нормально. Но если дополнить транзакцией
SQL
1
START TRANSACTION
То получается ошибка.
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,022
Записей в блоге: 3
11.12.2016, 14:30 20
Вычитал в документации, что открытии и закрытие в Builder/Delphi осуществляется не запросом, а настройками самих компонентов, типа так :
C++
1
2
3
4
5
6
FDConnection1->StartTransaction();
 
//сам запрос
 
 FDConnection1->Commit();
 FDConnection1->Rollback()
Ну собственно в разных компонентах для работы с БД, может немного синтаксис отличаться, но суть одна и тажа.
0
11.12.2016, 14:30
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.12.2016, 14:30
Помогаю со студенческими работами здесь

Транзакции в PHP+MySQL
Здраствуйте. Пишу форум и у меня такая задача. При создании темы юзер имеет право аттачить...

транзакции в C# при работе с MySQL
Доброго времени суток. В общем проблема такая. Пытаюсь использовать механизм транзакций в своем...

Транзакции на русском под сервер MySQL
Доброго всем времени суток. У меня появилась проблема решение которой я не могу найти достаточно...

Как сделать транзакции в mysql server?
В новой базе данных new_base создать таблицу счетов типа InnoDB (поле баланс действительного типа)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru