Qt escreve plataforma de gerenciamento de IoT 38-suporte a vários bancos de dados

I. Introdução

No início do projeto deste sistema, era necessário suportar uma variedade de bancos de dados diferentes, como sqlite, mysql, postgres, sqlserver, etc., e até mesmo bancos de dados domésticos, como NPC Jincang kingbase, etc. promoção vigorosa da localização, bancos de dados domésticos também devem ser suportados ), o módulo sql do componente de banco de dados encapsulado em Qt possui uma camada de abstração para todos os bancos de dados, o que torna uma boa premissa para a aplicação suportar vários bancos de dados, portanto, mais detalhes são tratados, como como consulta de intervalo de data do banco de dados, bancos de dados diferentes têm métodos de processamento diferentes, o que requer processamento diferente em seus próprios componentes encapsulados e paginação de banco de dados. As instruções de consulta de paginação de bancos de dados diferentes são diferentes. Por exemplo, sqlite e mysql usam a chave de limite. Word, Os bancos de dados postgres e kongbase usam a palavra-chave limit offset, sqlserver usa a palavra-chave top, oracle é o mais complicado e precisa ser combinado com colunas ocultas.

Algumas lições aprendidas com o banco de dados:

  • Não há conceito de tipo de dados no banco de dados sqlite, e o int que você define ainda pode armazenar strings. Outros bancos de dados têm distinções de tipo de dados.
  • Ao projetar campos de banco de dados, tente evitar palavras-chave de banco de dados e palavras-chave de função, como ano, mês, plano, etc. Se necessário, adicione aspas aos campos correspondentes ao executar instruções SQL.
  • Além do banco de dados sqlite, outros bancos de dados possuem requisitos de comprimento, como a configuração de 2, se você insistir em inserir o comprimento de 3, um erro será relatado e a execução não terá êxito.
  • O tipo varchar armazena strings, gbk codifica o próximo caractere chinês com 2 bytes, e utf8 codifica o próximo caractere chinês com 3 bytes, portanto deve ser considerado bem, como o conteúdo 'enable', é melhor definir o comprimento para 6 bytes.
  • Para reduzir o tamanho do arquivo de banco de dados o máximo possível, é recomendável definir o comprimento conhecido o máximo possível quando o comprimento do campo for conhecido.
  • Tabelas de banco de dados com um grande número de registros e tabelas que muitas vezes precisam ser consultadas devem ser indexadas, caso contrário, será muito lento.
  • Para uma tabela com uma pequena quantidade de dados, como menos de alguns milhares de entradas, e quase nenhuma alteração é necessária, não é necessário definir um índice, o que pode acelerar a velocidade de inserção.
  • O comprimento dos campos inteiros INT e INTEGER não pode ser definido e não há necessidade de definir o comprimento, caso contrário, um erro será relatado quando um banco de dados como sqlserver for executado.
  • Recomenda-se definir um campo de chave primária para cada tabela, principalmente a tabela que precisa ser indexada deve ter um campo de chave primária.
  • Instale o comando mysql client no linux: apt-get install libmysqlclient-dev.

Algum conhecimento frio sobre o desenvolvimento de banco de dados Qt.

  • Qt suporta a comunicação direta com o banco de dados na forma de uma biblioteca, e também suporta a comunicação com vários bancos de dados na forma de uma fonte de dados ODBC, que cobre todas as situações.
  • O programa de banco de dados Qt é empacotado e liberado, todos os pré-requisitos: preste atenção para distinguir entre 32 e 64 bits. Se seu programa for de 32 bits, você deve trazer bibliotecas de 32 bits. 64 bits deve trazer bibliotecas de 64 bits. Isso é também a biblioteca Qt. Requer. A maneira mais fácil de liberar o mysql é trazer um arquivo de biblioteca dinâmica do mysql (libmysql.dll no Windows), que é muito simples. sqlserver não precisa ser trazido, pois é filho da Microsoft, e o sistema operacional geral vem com ele. Postgres precisa trazer libpq.dll, libintl-8.dll, libiconv-2.dll, libeay32.dll, ssleay32.dll esses arquivos. O Oracle precisa trazer oci.dll e oraociei11.dll (este arquivo é muito grande e tem mais de 130 MB), caso contrário, é recomendável instalar um software cliente cliente oracle diretamente e, em seguida, definir o diretório bin correspondente para a variável de ambiente.
  • Depois que o pacote foi lançado e testado, descobriu-se que programas de 32 bits também podem se conectar ao mysql de 64 bits normalmente, e programas de 64 bits também podem se conectar ao mysql de 32 bits normalmente. o número de bits na biblioteca do programa é o mesmo (ao compilar). Esta também é a regra, o plug-in de banco de dados de compilação de programa Qt de 32 bits também usa biblioteca de link de banco de dados de 32 bits.), não precisa ser consistente com o número de bancos de dados específicos, os bancos de dados mysql, sqlserver, postgresql testados são todas regras semelhantes.
  • Um grande número de testes são comparados, e um grande número de registros de dados são inseridos em lotes através do método de fonte de dados odbc e do método de conexão direta. O método de conexão direta é mais rápido, cerca de 5%, por isso é recomendável usar esse método Usando o método de fonte de dados odbc, o Qt vem com o plug-in de banco de dados odbc por padrão.
  • Bancos de dados diferentes converterão automaticamente o nome da tabela ou o nome do campo para maiúsculas ou minúsculas ao executar o script sql, o mysql converterá o nome da tabela para minúsculas, o postgresql converterá o nome da tabela e o nome do campo para minúsculas, o oracle converterá o nome da tabela e o campo nome Converter em maiúsculas. Isso leva ao fato de que ao usar QSqlTableModel para chamar setTable para definir o nome da tabela do banco de dados, ele deve ser igual ao nome da tabela no banco de dados e faz distinção entre maiúsculas e minúsculas, portanto, você deve prestar atenção aos bancos de dados postgresql e oracle. preso aqui por muito tempo, eu quase quero deduzir essa merda enorme no bug do Qt.
void DbHelper::bindTable(const QString &dbType, QSqlTableModel *model, const QString &table)
{
    
    
    //postgresql全部小写,oracle全部大写,这两个数据库严格区分表名字段名的大小写卧槽
    QString flag = dbType.toUpper();
    if (flag == "POSTGRESQL") {
    
    
        model->setTable(table.toLower());
    } else if (flag == "ORACLE") {
    
    
        model->setTable(table.toUpper());
    } else {
    
    
        model->setTable(table);
    }
}
  • O Qt suporta a abertura do banco de dados sem especificar o nome do banco de dados, pois às vezes é necessário executar a instrução sql para criar o banco de dados após conectar-se ao servidor de banco de dados. Como conectar o banco de dados ainda não existe, o teste descobriu que sqlite, mysql, sqlserver, postgresql todos suportam esse recurso. A premissa de excluir e criar um banco de dados é que o banco de dados não seja ocupado por outros programas, por exemplo, se outros programas já abriram o banco de dados, a execução falhará. Já fui torturado muitas vezes aqui, por que a execução falhou? Mais tarde, descobriu-se que a ferramenta de banco de dados de terceiros havia aberto o banco de dados e não havia problema em desativar a ferramenta.
QSqlDatabase database = QSqlDatabase::addDatabase("QMYSQL");
//database.setDatabaseName("dbtool");
database.setHostName("127.0.0.1");
database.setPort(3306);
database.setUserName("root");
database.setPassword("root");

if (database.open()) {
    
    
    QSqlQuery query(database);
    qDebug() << "删除数据库" << query.exec("drop database dbtool");
    qDebug() << "创建数据库" << query.exec("create database dbtool");
    if (query.exec("select * from userinfo")) {
    
    
        while (query.next()) {
    
    
            qDebug() << "查询数据库" << query.value(0);
        }
    }
} else {
    
    
     qDebug() << "打开数据库" << database.lastError().text();
}
  • Use QSqlQueryModel+QTableView para exibir os dados.Se os dados do tipo int excederem 1 milhão, eles se tornarão a exibição de notação científica, o que é muito chato, e definitivamente não é o resultado que você deseja. Depois de pesquisar por toda a Internet, finalmente encontrei um amigo com o mesmo problema, só preciso adicionar uma comissão vazia a esta coluna. Mais tarde, descobriu-se que as comissões vazias não são suficientes. Mais de 10 milhões de itens são muito ruins, e o modelo de dados precisa ser recarregado pelo Dafa final.
ui->tableView->setItemDelegateForColumn(0, new QItemDelegate);

//下面是终极大法
QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
{
    
    
    QVariant value = QSqlQueryModel::data(index, role);
    //超过100万的数值会被科学计数显示需要这里转成字符串显示
    if (role == Qt::DisplayRole) {
    
    
        int result = value.toInt();
        if (result >= 1000000) {
    
    
            value = QString::number(result);
        }
    }
    return value
}
  • O banco de dados mysql possui vários mecanismos de banco de dados, entre os quais o MyIsam não suporta transações de banco de dados. O padrão geralmente é esse mecanismo, portanto, quando você confirmar após usar o método de transação no Qt, verá que ele não foi bem-sucedido. Na verdade, foi bem-sucedido .Vá para o banco de dados Verifique os resultados correspondentes dentro e está correto. Existem duas maneiras, a primeira é alterar o mecanismo de banco de dados para InnoDB e a segunda é fazer um julgamento de erro após enviar se (database.commit() || !database.lastError().isValid()), o erro não está disponível. A descrição foi bem-sucedida.
  • Se você usar a comunicação da fonte de dados odbc, você só precisa definir o nome do banco de dados setDatabaseName, definir o nome de usuário setUserName, definir a senha do usuário setPassword esses três parâmetros, pois a configuração da fonte de dados já definiu o endereço do host e a porta correspondentes e o banco de dados associado name, portanto, você só precisa verificar as informações do usuário novamente ao se comunicar com a fonte de dados odbc. Atenção especial aqui é que setDatabaseName configura o nome do banco de dados para preencher o nome da configuração da fonte de dados.
  • Após muitos testes comparativos, incluindo operações como inserir, deletar, agrupar, consultar, paginar, etc., com dezenas de milhões de dados, na velocidade de resposta do banco de dados Qt, o ranking de facilidade é sqlite > postgresql > oracle > mysql > odbc . Dezenas de milhões ou mais são postgresql > oracle > mysql > sqlite > odbc . Acima do nível do bilhão está oracle > postgresql > other. Os testes acima são baseados no nível de iniciante, e vários pontos de conhecimento avançado, como sub-banco de dados e sub-tabela, consulta conjunta, cache, banco de dados de memória, etc. são inúteis.
  • Existem duas versões principais do mysql, mysql5.7 e mysql8. Oficialmente, 8 é muito mais rápido que 5. Após testes pessoais, 5.7 é muito mais rápido que 8. Seja consultando ou inserindo dados em lotes, não sei por que , mas pesquisei online. Esse também é o resultado ( https://www.coder4.com/archives/7596 ), todos disseram que 8 é muito mais lento.
  • Existe um ramo do mysql chamado mariadb, que é mais puro que o mysql. Diz-se que o mysql está travado em todos os aspectos ( https://blog.csdn.net/x275920/article/details/123847792 ), e a comparação pessoal test também é verdadeiro para inserção em lote e desempenho de consultas É muito melhor e é totalmente compatível com o mysql. Até mesmo o arquivo de biblioteca pode ser usado diretamente renomeando-o diretamente. Por exemplo, alterando libmariadb.dll para libmysql.dll pode ser usado diretamente, e o volume é oito vezes menor.Isso é bom, e é lançado com menos frequência.vários megabytes.
  • Se for um programa Qt+mysql, a versão da biblioteca quando lançada deve ser a mesma versão do banco de dados correspondente ao plug-in, caso contrário pode não haver recurso de transação de banco de dados e database.driver() ->hasFeature(QSqlDriver::Transactions) é falso.
  • QSqlTableModel é muito bem encapsulado, não carrega todos os dados de uma vez, mas carrega os dados necessários conforme a barra de rolagem é puxada e testa 100 milhões de tabelas, o que é muito rápido, o mesmo que milhares de tabelas.
  • Ao se conectar ao banco de dados da rede, se sua rede local tiver configurado um proxy, como usar um proxy no github e outros sites, você descobrirá que o programa de banco de dados Qt não pode ser conectado. Você precisa definir QNetworkProxyFactory::setUseSystemConfiguration(false para não usar o proxy local) ). Se você não for cuidadoso neste lugar, encontrará problemas e suas dúvidas sobre a vida.

2. Recursos

2.1 Módulos de software

  1. Módulo de monitoramento de equipamentos, incluindo monitoramento de dados (exibição de tabela), painel de equipamentos (exibição de painel), monitoramento de mapa (exibição de mapa), monitoramento de curva (exibição de curva).
  2. Módulo de consulta de dados, incluindo registro de alarme, registro de operação, registro de operação.
  3. Módulo de configuração do sistema, incluindo configuração básica, gerenciamento de porta, gerenciamento de controlador, gerenciamento de detector, ligação de alarme, configuração de tipo, etc.
  4. Outros módulos de configuração, incluindo gerenciamento de usuários, gerenciamento de mapas, ajuste de localização, design de configuração, depuração de equipamentos, etc.

2.2 Funções básicas

  1. Aquisição de dados do dispositivo, suporte a porta serial, rede, número da porta serial, taxa de transmissão pode ser definida, rede pode definir endereço IP, porta de comunicação.
  2. Cada porta suporta o tempo de ciclo de coleta, um dispositivo por segundo por padrão.
  3. Suporta a configuração do número de tempos limite de comunicação, o padrão é 3 vezes.
  4. Suporta tempo máximo de reconexão para releitura de dispositivos offline.
  5. Informações do controlador, você pode adicionar o nome do controlador, selecionar o endereço do controlador, o modelo do controlador e definir o número de detectores sob o controlador.
  6. Informações do detector, pode adicionar o número da etiqueta, modelo do detector, tipo de gás, símbolo de gás, valor de alarme alto, valor de alarme baixo, valor de buffer, valor claro, se habilitar, som de alarme, mapa de fundo, período de armazenamento, número de ponto decimal de conversão numérica, tempo de atraso do alarme, tipo de alarme (HH, LL, HL), etc.
  7. O gerenciamento de tipo pode configurar o modelo do controlador, modelo do detector, tipo de gás, símbolo de gás, etc.
  8. O mapa suporta importação e exclusão, e as posições de todos os detectores no mapa podem ser arrastadas e salvas livremente.
  9. Informações da porta, informações do controlador, informações do detector, informações do tipo, informações do usuário, etc., todos suportam importação, exportação, exportação para excel e impressão.
  10. Registros de operação, registros de alarme e registros de operação suportam consultas combinadas de várias condições, como período de tempo, controlador, detector, etc. Todos os registros suportam exportação para excel/pdf e impressão.
  11. Os dados dentro do intervalo de tempo especificado podem ser excluídos dos registros de execução, registros de alarme e registros de operação.
  12. As configurações do sistema podem selecionar o número máximo de registros armazenados na tabela correspondente, limpar automaticamente os dados iniciais e deixar espaço suficiente para armazenar dados importantes.
  13. O encaminhamento de SMS de alarme, suporta vários números de telefone celular de recebimento e pode definir o intervalo de envio, como envio instantâneo ou envio de todas as informações de alarme a cada 6 horas, se o conteúdo do SMS for muito longo, ele dividirá automaticamente várias mensagens SMS.
  14. Encaminhamento de mensagens de alarme, suporta várias caixas de correio de recebimento e pode definir o intervalo de envio, como envio instantâneo ou envio de todas as informações de alarme uma vez a cada 6 horas, e suporta o envio de anexos.
  15. Defina o título em chinês, título em inglês, caminho do logotipo, direitos autorais, etc. do software.
  16. Alterne as configurações para iniciar a execução, som de alarme, login automático, lembrar senha, etc.
  17. O som do alarme pode ser configurado para reproduzir os tempos, e o estilo da interface oferece 18 conjuntos de arquivos de skin para escolher.
  18. Gerenciamento de usuários, incluindo configuração de direitos do usuário, diferentes usuários podem ter diferentes direitos de módulo.
  19. Login de usuário e logout de usuário, você pode lembrar a senha e fazer login automaticamente, relatar uma mensagem de erro mais de três vezes e fechar o programa.
  20. Quatro modos de monitoramento, monitoramento de painel de dispositivo, monitoramento de mapa, monitoramento de dados de tabela e monitoramento de dados de curva, podem ser alternados livremente.Todos os quatro modos exibem os dados coletados em tempo real e o alarme pisca.
  21. Ligação de relé de alarme, um número de tag pode vincular vários módulos e números de relé na porta serial, suportando muitos para muitos.

2.3 Recursos

  1. O protocolo de comunicação suporta modbus_com, modbus_tcp_rtu e posteriormente expande protocolos como mqtt.
  2. Além da aquisição real do dispositivo de hardware, a fonte de dados também pode ser selecionada do banco de dados, para que o usuário possa organizar outros programadores, como programadores java, para colocar os dados coletados pelo front-end no banco de dados, e o sistema pode coletar do banco de dados. O modo de coleta de banco de dados pode ser usado como um sistema geral e é mais adequado para colaboração de várias pessoas e de vários sistemas.
  3. Pule de forma inteligente os dispositivos com horas extras e acelere a aquisição de dispositivos online, especialmente útil quando há um grande número de dispositivos.
  4. Para o dispositivo de tempo limite ignorado de forma inteligente, ele é coletado automaticamente uma vez no tempo de reconexão definido, para detectar se o dispositivo está online novamente.
  5. Cada detector pode ser controlado para ser ativado ou não. Caso não seja ativado, não será coletado e não será exibido na interface, o que equivale a desligar temporariamente durante a fase de execução.
  6. O detector pode definir um valor de buffer e um tempo de atraso de alarme. O alarme gerado por flutuações em torno desse valor não será contado como um alarme. Somente quando o detector estiver continuamente no valor de alarme e exceder o tempo de atraso de alarme, ele pode ser considerado como um alarme real, que pode evitar muitos erros causados ​​por flutuações.
  7. O detector pode definir o período de armazenamento e armazenar um registro de execução de acordo com o tempo definido. De acordo com o grau de importância, o período de armazenamento da configuração de alta importância pode ser menor e a configuração sem importância pode ser maior, o que pode economizar muito espaço de armazenamento. , e também garante que os dados importantes sejam armazenados em tempo hábil.
  8. O detector pode ser configurado para um valor de reinicialização. Quando alguns equipamentos de alta precisão e alta sensibilidade podem sair da fábrica, o valor padrão pode não ser 0. É necessário configurar o valor de reinicialização para representar o valor inicial.
  9. O detector pode definir um ponto decimal, que é usado para controlar a exibição do ponto decimal dos dados reais após o cálculo, o que equivale a dividir por 10, 100 e 1000. Dessa forma, a maioria dos dados do detector pode ser controlada diretamente pelo ajuste do ponto decimal para controlar o valor real convertido.Valores, muito poucos que requerem conversão especial podem ser acordados no protocolo de comunicação.
  10. Existem muitos tipos de alarmes de detector. Alguns dispositivos relatam relatórios altos acima de um determinado valor e relatórios baixos abaixo de um determinado valor, enquanto alguns dispositivos relatam relatórios altos dentro da faixa dos valores mínimo e máximo e relatórios baixos abaixo do valor mínimo. Acima o valor máximo é normal. Isso permite o tratamento caso a caso, abrangendo vários tipos de alarme.
  11. Mecanismo de importação, exportação e impressão de dados originais, multiplataforma sem depender de nenhum componente e exportação de dados instantaneamente.
  12. Os registros exportados para o Excel suportam todas as versões do Excel, wps e outros arquivos de formulário e não dependem do Excel e de outros softwares.
  13. Cor de relatório alta, cor de relatório baixa, cor normal, cor de valor padrão, etc., podem ser definidas livremente.
  14. Dê suporte à sincronização de dados na nuvem e sincronize os dados coletados localmente com a nuvem em tempo real.
  15. Suporta encaminhamento de rede e recepção de rede Após a ativação da recepção de rede, o software recebe dados do udp para análise. O encaminhamento de rede suporta vários IPs de destino, para que o software de coleta local possa ser transferido livremente para o cliente e os dados coletados possam ser visualizados a qualquer momento.
  16. Lembre-se automaticamente da última interface do usuário e de outras informações de configuração e aplique-as automaticamente após a reinicialização.
  17. O alarme muda automaticamente para o mapa correspondente, o botão do detector pisca e os dados da tabela são exibidos na cor correspondente.
  18. Clique duas vezes no ícone do detector para exibir as informações detalhadas do detector correspondente e você pode personalizar a operação de retorno de chamada de acordo com suas necessidades.
  19. O banco de dados suporta uma variedade de bancos de dados, incluindo sqlite, mysql, sqlserver, postgresql, oracle, NPC Jincang, etc.
  20. Os dados coletados pelo dispositivo local são carregados na nuvem em tempo real, para que possam ser extraídos por outros métodos como APP móvel ou web.
  21. A ferramenta de simulação de dispositivo integrada suporta simulação de dados de vários dispositivos de modelos diferentes e também possui simulação de dados de banco de dados para testar dados quando não houver dispositivo.
  22. O protocolo modbus padrão, vários tipos de controladores, tipos de detectores, tipos, símbolos, etc. são todos personalizados, muito flexíveis e poderosos, os dados de amostra do protocolo de comunicação são muito completos, comuns a vários sistemas de protocolo modbus, adequados para acesso a vários cenários de aplicação.
  23. Ao mesmo tempo, ele integra muitos componentes e pontos de conhecimento, como comunicação serial, comunicação de rede, comunicação de banco de dados, importação, exportação e impressão de dados, análise de protocolo de comunicação, interface do usuário e skin global, o que é muito adequado para iniciantes e jogadores avançados .
  24. Suporta xp, win7, win10, win11, linux, mac, vários sistemas domésticos (UOS, ganhando kylin, galaxy kylin, etc.), linux embutido e outros sistemas.
  25. Comentários completos, estrutura clara do projeto, manual de uso e desenvolvimento super detalhado e completo, preciso na descrição funcional de cada arquivo de código e versões iterativas contínuas.

3. Endereço da experiência

  1. Site doméstico: https://gitee.com/feiyangqingyun
  2. Site internacional: https://github.com/feiyangqingyun
  3. Página pessoal: https://blog.csdn.net/feiyangqingyun
  4. Conheça a página inicial: https://www.zhihu.com/people/feiyangqingyun
  5. Página inicial do produto: https://blog.csdn.net/feiyangqingyun/article/details/97565652
  6. Documentação online: https://feiyangqingyun.gitee.io/qwidgetdemo/iotsystem/
  7. Endereço da experiência: https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A Código de extração: o05q Nome do arquivo: bin_iotsystem.zip.
  8. Navegação do artigo: https://qtchina.blog.csdn.net/article/details/121330922

Quarto, o mapa de efeitos

insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui

5. Código relevante

void frmConfigDb::on_btnConnect_clicked()
{
    
    
    {
    
    
        //初始化数据库连接信息结构体数据
        DbInfo dbInfo;
        initDbInfo(dbInfo, connName);

        QString dbType = AppConfig::LocalDbType.toUpper();
        if (dbType == "SQLITE") {
    
    
            dbInfo.dbName = DbHelper::getDbDefaultFile(connFlag);
            if (QFile(dbInfo.dbName).size() <= 4) {
    
    
                QUIHelper::showMessageBoxError("数据库文件不存在!", 5);
                return;
            }
        }

        QSqlDatabase database;
        if (DbHelper::initDatabase(true, dbType, database, dbInfo)) {
    
    
            if (database.open()) {
    
    
                database.close();
                QUIHelper::showMessageBoxInfo("打开数据库成功!", 3);
            } else {
    
    
                QString error = database.lastError().text();
                QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3);
            }
        } else {
    
    
            QString error = database.lastError().text();
            QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3);
        }
    }

    QSqlDatabase::removeDatabase(connName);
}

void frmConfigDb::on_btnInit_clicked()
{
    
    
    if (QUIHelper::showMessageBoxQuestion("确定要初始化数据库吗? 会全部清空数据并且不可还原!") != QMessageBox::Yes) {
    
    
        return;
    }

    QString sqlName = QString("%1/db/%2.sql").arg(QUIHelper::appPath()).arg(connFlag);
    QFile file(sqlName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    
    
        QUIHelper::showMessageBoxError("数据库脚本文件打开失败!", 3);
        return;
    }

    QElapsedTimer time;
    time.start();
    {
    
    
        //初始化数据库连接信息结构体数据
        DbInfo dbInfo;
        initDbInfo(dbInfo, connName);

        QString dbType = AppConfig::LocalDbType.toUpper();
        if (dbType == "SQLITE") {
    
    
            dbInfo.dbName = DbHelper::getDbDefaultFile(connFlag);
            //如果文件存在则先删除原来的数据库文件,貌似win上不行
            QFile file(dbInfo.dbName);
            if (file.exists()) {
    
    
                bool ok = file.remove();
                if (!ok) {
    
    
                    qDebug() << TIMEMS << "remove error" << dbInfo.dbName;
                }

                //清空所有表
                QStringList tables = QSqlDatabase::database().tables();
                foreach (QString table, tables) {
    
    
                    DbHelper::clearTable(table, dbType);
                    qDebug() << TIMEMS << "clearTable" << table;
                }

                //关闭默认数据库连接
                QSqlDatabase::database().close();
            }
        }

        //初始化数据库连接并打开数据库
        QSqlDatabase database;
        if (!DbHelper::initDatabase(true, dbType, database, dbInfo)) {
    
    
            QString error = database.lastError().text();
            QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3);
            return;
        }
        if (!database.open()) {
    
    
            QString error = database.lastError().text();
            QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3);
            return;
        }

        QSqlQuery query(QSqlDatabase::database(connName));

        //第一步:删除原有数据库
        QString sql = QString("DROP DATABASE %1;").arg(dbInfo.dbName);
        qDebug() << TIMEMS << "sql:" << sql << "result:" << query.exec(sql);

        //第二步:新建数据库
        sql = QString("CREATE DATABASE %1;").arg(dbInfo.dbName);
        qDebug() << TIMEMS << "sql:" << sql << "result:" << query.exec(sql);

        //第三步:切换到新建的数据库库并执行建表语句
        database.close();
        if (!DbHelper::initDatabase(false, dbType, database, dbInfo)) {
    
    
            QString error = database.lastError().text();
            QUIHelper::showMessageBoxError("连接数据库失败!\n" + error, 3);
            return;
        }
        if (!database.open()) {
    
    
            QString error = database.lastError().text();
            QUIHelper::showMessageBoxError("打开数据库失败!\n" + error, 3);
            return;
        }

        //将执行出错的sql语句输出到文件方便查看
        QString fileName2 = QString("%1/db/error.sql").arg(QUIHelper::appPath());
        QFile file2(fileName2);

        QSqlQuery query2(QSqlDatabase::database(connName));

        sql = "BEGIN;";
        qDebug() << TIMEMS << "sql:" << sql << "result:" << query2.exec(sql);

        while (!file.atEnd()) {
    
    
            sql = QString::fromUtf8(file.readLine());
            sql.replace("\n", "");

            //有些数据库不支持的语句跳过去
            if (DbHelper::existNoSupportSql(sql)) {
    
    
                continue;
            }

            //重新纠正sql语句
            DbHelper::checkSql(dbType, sql);

            if (!query2.exec(sql)) {
    
    
                //打印及输出错误信息
                QString error = query2.lastError().text();
                qDebug() << TIMEMS << "sql:" << sql << error;

                //没打开则先打开
                if (!file2.isOpen()) {
    
    
                    file2.open(QFile::WriteOnly | QFile::Append);
                }

                QString msg = QString("时间[%1]  语句: %2  错误: %3\n").arg(DATETIME).arg(sql).arg(error);
                file2.write(msg.toUtf8());
            }
        }

        sql = "COMMIT;";
        qDebug() << TIMEMS << "sql:" << sql << "result:" << query2.exec(sql);
        database.close();

        //sqlite数据库的话再执行下压缩减少体积
        if (dbType == "SQLITE") {
    
    
            DbHelper::execSql("VACUUM;");
        }
    }

    QSqlDatabase::removeDatabase(connName);
    double ms = time.elapsed();
    QString info = QString("数据库脚本执行成功, 总共用时 %1 秒!\n记得重新启动程序!").arg(QString::number(ms / 1000, 'f', 1));
    QUIHelper::showMessageBoxInfo(info, 3);
}

void frmConfigDb::on_cboxDbType_activated(int)
{
    
    
    //自动切换默认端口号和其他信息
    QString hostPort, userName, userPwd;
    QString dbType = ui->cboxDbType->currentText().toUpper();
    DbHelper::getDbDefaultInfo(dbType, hostPort, userName, userPwd);
    if (!hostPort.isEmpty() && AppConfig::LocalAutoInfo) {
    
    
        QStringList hostInfo = ui->txtHostInfo->text().split(":");
        ui->txtHostInfo->setText(hostInfo.at(0) + ":" + hostPort);
        ui->txtUserName->setText(userName);
        ui->txtUserPwd->setText(userPwd);
    }
}

Acho que você gosta

Origin blog.csdn.net/feiyangqingyun/article/details/125593804
Recomendado
Clasificación