当前位置: 首页 > ai >正文

Jfinal+SQLite解决MYSQL迁移表未复制索引问题,完善迁移工具

原mysql 表查询存在索引,

查询sql含force index(字段),SQLite不支持,会报错

解决办法,要么删除索引,要么强制执行索引 换成 INDEXED BY, 

String select sql="select * ";

String fromSql=" from tableName force index (START_TIME_TYPE) where 1=1

if (fromSql.contains("force index")){fromSql= fromSql.replaceAll("(?i)\\bFROM\\s+(\\w+)(\\s+\\w+)?\\s+force\\s+index\\s*\\(\\s*(\\w+)\\s*\\)","FROM $1 $2 INDEXED BY $3");
}

这里就需要给sqlite数据库表添加对应索引,不然会报错SQLiteException: no such index: START_TIME_TYPE

生产数据库中,表多,索引比较多,在原先迁移表工具添加索引迁移,暂时未发现问题,需多多测试

package changeDataBase;import java.sql.*;
import java.util.*;public class MySQLToSQLiteMigration {private static final String MYSQL_URL = "jdbc:mysql://localhost:3306/database";private static final String MYSQL_USER = "admin";private static final String MYSQL_PASSWORD = "123456";private static final String SQLITE_URL = "jdbc:sqlite:D:/database/database.sqlite";public static void main(String[] args) {try {Class.forName("org.sqlite.JDBC");} catch (ClassNotFoundException var2) {System.err.println("SQLite JDBC driver not found!");var2.printStackTrace();return;}List<String> tableNames = getTableNamesFromMySQL();migrateTablesToSQLite(tableNames);}private static List<String> getTableNamesFromMySQL() {ArrayList<String> tableNames = new ArrayList<>();try (Connection conn = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASSWORD)) {DatabaseMetaData metaData = conn.getMetaData();ResultSet rs = metaData.getTables(null, null, "%", new String[]{"TABLE"});while (rs.next()) {tableNames.add(rs.getString("TABLE_NAME"));}} catch (SQLException var6) {var6.printStackTrace();}return tableNames;}private static void migrateTablesToSQLite(List<String> tableNames) {try (Connection mysqlConn = DriverManager.getConnection(MYSQL_URL, MYSQL_USER, MYSQL_PASSWORD);Connection sqliteConn = DriverManager.getConnection(SQLITE_URL)) {Iterator<String> var3 = tableNames.iterator();while (var3.hasNext()) {String tableName = var3.next();System.out.println("Migrating table: " + tableName);migrateTable(mysqlConn, sqliteConn, tableName);}} catch (SQLException var9) {var9.printStackTrace();}}private static void migrateTable(Connection mysqlConn, Connection sqliteConn, String tableName) throws SQLException {String selectSql = "SELECT * FROM " + tableName;try (Statement stmt = mysqlConn.createStatement();ResultSet rs = stmt.executeQuery(selectSql)) {String createTableSql = getCreateTableSql(mysqlConn, tableName);try (Statement sqliteStmt = sqliteConn.createStatement()) {sqliteStmt.execute(createTableSql);}String insertSql = getInsertSql(rs.getMetaData(), tableName);try (PreparedStatement sqlitePstmt = sqliteConn.prepareStatement(insertSql)) {while (rs.next()) {for (int i = 1; i <= rs.getMetaData().getColumnCount(); ++i) {String columnName = rs.getMetaData().getColumnName(i);String columnType = rs.getMetaData().getColumnTypeName(i);// 特殊处理时间字段if ("DATETIME".equalsIgnoreCase(columnType) || "TIMESTAMP".equalsIgnoreCase(columnType)) {Object value = rs.getObject(i);if (value instanceof java.sql.Timestamp) {// 将 Timestamp 转换为标准日期时间格式java.sql.Timestamp timestamp = (java.sql.Timestamp) value;sqlitePstmt.setString(i, timestamp.toString());} else {sqlitePstmt.setObject(i, value);}} else {sqlitePstmt.setObject(i, rs.getObject(i));}}sqlitePstmt.addBatch();}sqlitePstmt.executeBatch();}}//处理索引migrateIndexes(mysqlConn, sqliteConn, tableName);}private static String getCreateTableSql(Connection mysqlConn, String tableName) throws SQLException {DatabaseMetaData metaData = mysqlConn.getMetaData();ResultSet rs = metaData.getColumns(null, null, tableName, "%");StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS ");sb.append(tableName).append(" (");List<String> columns = new ArrayList<>();String primaryKey = null;while (rs.next()) {String columnName = rs.getString("COLUMN_NAME");String columnType = getSQLiteType(rs.getString("TYPE_NAME"));columns.add(columnName + " " + columnType);}// 获取主键信息String primaryKeySql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND CONSTRAINT_NAME = 'PRIMARY'";try (PreparedStatement pstmt = mysqlConn.prepareStatement(primaryKeySql)) {pstmt.setString(1, "database");pstmt.setString(2, tableName);try (ResultSet pkRs = pstmt.executeQuery()) {if (pkRs.next()) {primaryKey = pkRs.getString("COLUMN_NAME");}}}sb.append(String.join(", ", columns));if (primaryKey != null) {sb.append(", PRIMARY KEY (").append(primaryKey).append(")");}sb.append(");");return sb.toString();}private static String getInsertSql(ResultSetMetaData metaData, String tableName) throws SQLException {StringBuilder sb = new StringBuilder("INSERT INTO ").append(tableName).append(" (");for (int i = 1; i <= metaData.getColumnCount(); ++i) {sb.append(metaData.getColumnName(i));if (i < metaData.getColumnCount()) {sb.append(", ");}}sb.append(") VALUES (");for (int i = 1; i <= metaData.getColumnCount(); ++i) {sb.append("?");if (i < metaData.getColumnCount()) {sb.append(", ");}}sb.append(");");return sb.toString();}private static String getSQLiteType(String mysqlType) {switch (mysqlType.toUpperCase()) {case "INT":case "INTEGER":return "INTEGER";case "VARCHAR":case "CHAR":return "TEXT";case "DATE":return "DATE";case "DATETIME":case "TIMESTAMP":return "DATETIME";case "DECIMAL":return "NUMERIC";case "FLOAT":case "DOUBLE":return "REAL";default:return "TEXT";}}//添加索引处理/*** 把 MySQL 表中除主键外的所有索引迁移到 SQLite*/private static void migrateIndexes(Connection mysqlConn,Connection sqliteConn,String tableName) throws SQLException {// 1. 先查索引列String sql ="SELECT INDEX_NAME, NON_UNIQUE, COLUMN_NAME, SEQ_IN_INDEX " +"FROM INFORMATION_SCHEMA.STATISTICS " +"WHERE TABLE_SCHEMA = DATABASE() " +"  AND TABLE_NAME   = ? " +"  AND INDEX_NAME  != 'PRIMARY' " +"ORDER BY INDEX_NAME, SEQ_IN_INDEX";// Map<索引名, 列列表>Map<String, List<String>> indexMap = new LinkedHashMap<>();try (PreparedStatement ps = mysqlConn.prepareStatement(sql)) {ps.setString(1, tableName);try (ResultSet rs = ps.executeQuery()) {while (rs.next()) {String idxName = rs.getString("INDEX_NAME");indexMap.computeIfAbsent(idxName, k -> new ArrayList<>()).add("\"" + rs.getString("COLUMN_NAME") + "\"");}}}// 2. 逐个在 SQLite 建索引for (Map.Entry<String, List<String>> e : indexMap.entrySet()) {String cols = String.join(", ", e.getValue());// 索引名在 SQLite 中保持同名,避免冲突可加前缀String createIdx = String.format("CREATE %s INDEX IF NOT EXISTS \"%s\" ON \"%s\" (%s);",e.getKey().toUpperCase().startsWith("UNIQUE") ? "UNIQUE" : "",e.getKey(), tableName, cols);try (Statement st = sqliteConn.createStatement()) {st.execute(createIdx);System.out.println("    " + createIdx.trim());}}}}
http://www.xdnf.cn/news/15603.html

相关文章:

  • AI问答-供应链管理:各种交通运输方式货运成本分析
  • 20.轮廓特征与近似,改变图像的轮廓识别画线的精确度,同时画出轮廓对应的矩形
  • 下载了docker但是VirtualBox突然启动不了了
  • Redis:哨兵(Sentinel)
  • Jmeter使用 -1
  • EPLAN 电气制图(十): 绘制继电器控制回路从符号到属性设置(上)
  • python学智能算法(二十二)|SVM-点与超平面的距离
  • 征程 6 UCP 任务优先级 抢占简介与实操
  • 1. 【面试题】- 盒马鲜生(上)
  • 【通识】网络的基础知识
  • MySQL配置性能优化
  • centos 新加磁盘分区动态扩容
  • Curtain e-locker易锁防泄密:从源头把关“打印”安全
  • 从零开始学 Linux 系统安全:基础防护与实战应用
  • Java 集合框架详解:Collection 接口全解析,从基础到实战
  • SpringBoot一Web Flux、函数式Web请求的使用、和传统注解@Controller + @RequestMapping的区别
  • 理解 PS1/PROMPT 及 macOS iTerm2 + zsh 终端配置优化指南
  • PySide笔记之信号连接信号
  • 【LeetCode 热题 100】230. 二叉搜索树中第 K 小的元素——中序遍历
  • Hyperledger Fabric:构建企业区块链网络的实践指南
  • 力扣 hot100 Day47
  • H3CNE 综合实验二解析与实施指南
  • S7-1200 模拟量模块全解析:从接线到量程计算
  • 如何清除 npm 缓存
  • 一台显示器上如何快速切换两台电脑主机?
  • LAMP迁移LNMP Nginx多站点配置全流程
  • 进程终止机制详解:退出场景、退出码与退出方式全解析
  • Transformer从入门到精通
  • 文件夹颜色更改工具 FolderIco 8.1
  • 面试高频题 力扣 200.岛屿数量 洪水灌溉 深度优先遍历 暴力搜索 C++解题思路 每日一题