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

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.dtcms.com/a/285625.html

相关文章:

  • 私有服务器AI智能体搭建-大模型选择优缺点、扩展性、可开发
  • 数组/链表/【环形数组】实现 队列/栈/双端队列【移动语义应用】【自动扩缩】
  • st-Gcn训练跳绳识别模型六:YOLOv8-Pose 和 ST-GCN 实现实时跳绳计数器应用
  • IDEA 2020.1版本起下载JDK
  • 当OT遇见IT:Apache IoTDB如何用“时序空间一体化“技术破解工业物联网数据孤岛困局?
  • 【每日算法】专题十三_队列 + 宽搜(bfs)
  • 四、CV_GoogLeNet
  • 代码训练营DAY35 第九章 动态规划part03
  • 【收集电脑信息】collect_info.sh
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 基于jieba实现词频统计
  • Kubernetes Pod深度理解
  • 【数据可视化-67】基于pyecharts的航空安全深度剖析:坠毁航班数据集可视化分析
  • 【问题解决】npm包下载速度慢
  • 【AI大模型学习路线】第三阶段之RAG与LangChain——第十八章(基于RAGAS的RAG的评估)RAG中的评估思路?
  • 把握流程节点,明确信息传递
  • C专题5:函数进阶和递归
  • 最小生成树算法详解
  • 2025外卖江湖:巨头争霸,谁主沉浮?
  • 洞见AI时代数据底座的思考——YashanDB亮相2025可信数据库发展大会
  • NIO网络通信基础
  • AndroidX中ComponentActivity与原生 Activity 的区别
  • 关于字符编辑器vi、vim版本的安装过程及其常用命令:
  • 从抓包GitHub Copilot认证请求,认识OAuth 2.0技术
  • web3 区块链技术与用
  • 基于深度学习的语音识别:从音频信号到文本转录
  • 开源的大语言模型(LLM)应用开发平台Dify
  • 如何用Python并发下载?深入解析concurrent.futures 与期物机制
  • 服务攻防-Java组件安全FastJson高版本JNDI不出网C3P0编码绕WAF写入文件CI链
  • ARM64高速缓存,内存属性及MAIR配置
  • 预测导管原位癌浸润性复发的深度学习:利用组织病理学图像和临床特征