Хорошо, я записал это принимающее во внимание, что было сказано в этом потоке. Спасибо за справку, и я надеюсь, что этот сценарий выручит других. У меня нет гарантии для ее использования, поэтому СКОПИРУЙТЕ прежде, чем выполнить ее. Это должно работа со всеми базами данных; и это работало отлично самостоятельно.
РЕДАКТИРОВАНИЕ: Добавленный Вар наверху, для который набор символов/сопоставлять преобразовать в. EDIT2: Изменяет набор символов/сопоставлять базы данных и таблиц по умолчанию
<?php
function MysqlError()
{
if (mysql_errno())
{
echo "<b>Mysql Error: " . mysql_error() . "</b>\n";
}
}
$username = "root";
$password = "";
$db = "database";
$host = "localhost";
$target_charset = "utf8";
$target_collate = "utf8_general_ci";
echo "<pre>";
$conn = mysql_connect($host, $username, $password);
mysql_select_db($db, $conn);
$tabs = array();
$res = mysql_query("SHOW TABLES");
MysqlError();
while (($row = mysql_fetch_row($res)) != null)
{
$tabs[] = $row[0];
}
// now, fix tables
foreach ($tabs as $tab)
{
$res = mysql_query("show index from {$tab}");
MysqlError();
$indicies = array();
while (($row = mysql_fetch_array($res)) != null)
{
if ($row[2] != "PRIMARY")
{
$indicies[] = array("name" => $row[2], "unique" => !($row[1] == "1"), "col" => $row[4]);
mysql_query("ALTER TABLE {$tab} DROP INDEX {$row[2]}");
MysqlError();
echo "Dropped index {$row[2]}. Unique: {$row[1]}\n";
}
}
$res = mysql_query("DESCRIBE {$tab}");
MysqlError();
while (($row = mysql_fetch_array($res)) != null)
{
$name = $row[0];
$type = $row[1];
$set = false;
if (preg_match("/^varchar\((\d+)\)$/i", $type, $mat))
{
$size = $mat[1];
mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARBINARY({$size})");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARCHAR({$size}) CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
else if (!strcasecmp($type, "CHAR"))
{
mysql_query("ALTER TABLE {$tab} MODIFY {$name} BINARY(1)");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARCHAR(1) CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
else if (!strcasecmp($type, "TINYTEXT"))
{
mysql_query("ALTER TABLE {$tab} MODIFY {$name} TINYBLOB");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} TINYTEXT CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
else if (!strcasecmp($type, "MEDIUMTEXT"))
{
mysql_query("ALTER TABLE {$tab} MODIFY {$name} MEDIUMBLOB");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} MEDIUMTEXT CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
else if (!strcasecmp($type, "LONGTEXT"))
{
mysql_query("ALTER TABLE {$tab} MODIFY {$name} LONGBLOB");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} LONGTEXT CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
else if (!strcasecmp($type, "TEXT"))
{
mysql_query("ALTER TABLE {$tab} MODIFY {$name} BLOB");
MysqlError();
mysql_query("ALTER TABLE {$tab} MODIFY {$name} TEXT CHARACTER SET {$target_charset}");
MysqlError();
$set = true;
echo "Altered field {$name} on {$tab} from type {$type}\n";
}
if ($set)
mysql_query("ALTER TABLE {$tab} MODIFY {$name} COLLATE {$target_collate}");
}
// re-build indicies..
foreach ($indicies as $index)
{
if ($index["unique"])
{
mysql_query("CREATE UNIQUE INDEX {$index["name"]} ON {$tab} ({$index["col"]})");
MysqlError();
}
else
{
mysql_query("CREATE INDEX {$index["name"]} ON {$tab} ({$index["col"]})");
MysqlError();
}
echo "Created index {$index["name"]} on {$tab}. Unique: {$index["unique"]}\n";
}
// set default collate
mysql_query("ALTER TABLE {$tab} DEFAULT CHARACTER SET {$target_charset} COLLATE {$target_collate}");
}
// set database charset
mysql_query("ALTER DATABASE {$db} DEFAULT CHARACTER SET {$target_charset} COLLATE {$target_collate}");
mysql_close($conn);
echo "</pre>";
?>
Есть ли другой способ, которым обычно восстановиться после таких ошибок, когда вы хочу повторить операцию после обработка исключения?
Да, в вызывающем коде. Позвольте вызывающей стороне этого метода решить, нужно ли им повторить логику или нет.
ОБНОВЛЕНИЕ:
Чтобы уточнить, вы должны перехватывать исключения, только если вы действительно можете их обработать. Ваш код в основном говорит:
"Я понятия не имею, что произошло, но что бы я ни сделал, все взорвите ... так что давайте сделаем это снова. "
Перехватите определенные ошибки, от которых вы можете избавиться, и позвольте остальным пузыриться на следующий уровень, чтобы обработать их. Любые исключения, которые доходят до самого верха, представляют истинные ошибки на этом этапе.
ОБНОВЛЕНИЕ 2:
Хорошо, поэтому вместо того, чтобы продолжать довольно продолжительное обсуждение с помощью комментариев, я подробно остановлюсь на примере полупсевдокода.
Общая идея заключается в том, что вам просто нужно чтобы реструктурировать код для выполнения тестов и немного улучшить взаимодействие с пользователем.
//The main thread might look something like this
try{
var database = LoadDatabaseFromUserInput();
//Do other stuff with database
}
catch(Exception ex){
//Since this is probably the highest layer,
// then we have no clue what just happened
Logger.Critical(ex);
DisplayTheIHaveNoIdeaWhatJustHappenedAndAmGoingToCrashNowMessageToTheUser(ex);
}
//And here is the implementation
public IDatabase LoadDatabaseFromUserInput(){
IDatabase database = null;
userHasGivenUpAndQuit = false;
//Do looping close to the control (in this case the user)
do{
try{
//Wait for user input
GetUserInput();
//Check user input for validity
CheckConfigFile();
CheckDatabaseConnection();
//This line shouldn't fail, but if it does we are
// going to let it bubble up to the next layer because
// we don't know what just happened
database = LoadDatabaseFromSettings();
}
catch(ConfigFileException ex){
Logger.Warning(ex);
DisplayUserFriendlyMessage(ex);
}
catch(CouldNotConnectToDatabaseException ex){
Logger.Warning(ex);
DisplayUserFriendlyMessage(ex);
}
finally{
//Clean up any resources here
}
}while(database != null);
}
Теперь, очевидно, я понятия не имею, что пытается сделать ваше приложение, и это, безусловно, не производственный пример. Надеюсь, вы получите Общая идея. Перестройте программу, чтобы избежать ненужных перерывов в работе приложения.
Ура, Джош
Возможно, я что-то упускаю, но почему вы не можете просто использовать цикл while? это даст вам один и тот же цикл навсегда, если у вас есть функция исключения (что является плохим кодом), которую дает ваш код.
IDatabase database = null;
while(database == null){
try
{
database = databaseLoader.LoadDatabase();
}
catch(Exception e)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
//just in case??
database = null;
}
}
если вам нужно использовать goto в обычном коде, вам не хватает логического потока. которые вы можете получить, используя стандартные конструкции, if, while, и т. д.
Лично я бы использовал это в отдельном методе, который возвращает код состояния успеха или неудачи. Затем в коде, который будет вызывать этот метод, у меня может быть какое-то магическое количество раз, когда я буду продолжать попытки, пока код состояния не станет «Успех». Мне просто не нравится использовать try / catch для потока управления.
Понятно? На самом деле, нет. Я думаю, что вы действительно хотите сначала загрузить базу данных, а затем, если это не сработало, попробовать загрузить ее другим способом. Это правильно? Давайте так и напишем код.
IDatabase loadedDatabase = null;
// first try
try
{
loadedDatabase = databaseLoader.LoadDatabase();
}
catch(Exception e) { } // THIS IS BAD DON'T DO THIS
// second try
if(loadedDatabase == null)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
loadedDatabase = databaseLoader.LoadDatabase()
}
Это более ясно показывает, что вы на самом деле делаете. В качестве дополнительного бонуса другие программисты не выколют вам глаза. :)
ПРИМЕЧАНИЕ: вы почти наверняка не хотите перехватывать исключение. Вероятно, есть более конкретное исключение, которое вы бы предпочли поймать. Это также приведет к перехвату TheComputerIsOnFireException, после чего повторять попытку не стоит.
s напишите код таким образом.IDatabase loadedDatabase = null;
// first try
try
{
loadedDatabase = databaseLoader.LoadDatabase();
}
catch(Exception e) { } // THIS IS BAD DON'T DO THIS
// second try
if(loadedDatabase == null)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
loadedDatabase = databaseLoader.LoadDatabase()
}
Это более ясно показывает, что вы на самом деле делаете. В качестве дополнительного бонуса другие программисты не выколачивают вам глаза. :)
ПРИМЕЧАНИЕ: вы почти наверняка не хотите перехватывать Exception. Вероятно, есть более конкретное исключение, которое вы бы предпочли уловить. Это также приведет к перехвату TheComputerIsOnFireException, после чего повторять попытку не стоит.
s напишите код таким образом.IDatabase loadedDatabase = null;
// first try
try
{
loadedDatabase = databaseLoader.LoadDatabase();
}
catch(Exception e) { } // THIS IS BAD DON'T DO THIS
// second try
if(loadedDatabase == null)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
loadedDatabase = databaseLoader.LoadDatabase()
}
Это более ясно показывает, что вы на самом деле делаете. В качестве дополнительного бонуса другие программисты не выколачивают вам глаза. :)
ПРИМЕЧАНИЕ: вы почти наверняка не хотите перехватывать исключение. Вероятно, есть более конкретное исключение, которое вы бы предпочли поймать. Это также приведет к обнаружению исключения TheComputerIsOnFireException, после чего повторять попытку не стоит.
Кстати, я думаю, что существует вероятность бесконечного цикла, если вы всегда получаете исключение.
Технически в вашей структуре goto нет ничего плохого, но я бы предпочел вместо этого использовать цикл while. Что-то вроде:
IDatabase database = null;
bool bSuccess = false;
int iTries = 0
while (!bSuccess) // or while (database == null)
{
try
{
iTries++;
database = databaseLoader.LoadDatabase();
bSuccess = true;
}
catch(DatabaseLoaderException e)
{
//Avoid an endless loop
if (iTries > 10)
throw e;
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
}
}