YumCore/src/main/java/pw/yumc/YumCore/sql/DataBase.java

481 lines
16 KiB
Java
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package pw.yumc.YumCore.sql;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.bukkit.P;
import pw.yumc.YumCore.config.inject.InjectParse;
import pw.yumc.YumCore.config.inject.InjectParse.Parse;
import pw.yumc.YumCore.sql.core.DataBaseCore;
import pw.yumc.YumCore.sql.core.KeyValue;
import pw.yumc.YumCore.sql.core.MySQLCore;
import pw.yumc.YumCore.sql.core.SQLiteCore;
/**
* 数据库管理类
*
* @since 2015年12月14日 下午1:26:06
* @author 喵♂呜
*
*/
public class DataBase {
private DataBaseCore dataBaseCore;
/**
* 初始化数据库管理
*
* @param core
* 数据库核心
*/
public DataBase(DataBaseCore core) {
this.dataBaseCore = core;
}
public static DataBase create(Plugin plugin, ConfigurationSection dbConfig) {
ConfigurationSection cfg = dbConfig.getConfigurationSection("MySQL");
if (dbConfig.getString("FileSystem").equalsIgnoreCase("MySQL")) {
plugin.getLogger().info("已启用MySQL保存数据,开始连接数据库...");
return new DataBase(new MySQLCore(cfg));
}
return new DataBase(new SQLiteCore(plugin, cfg));
}
/**
* 关闭数据库连接
*
* @return 是否关闭成功
*/
public boolean close() {
try {
this.dataBaseCore.getConnection().close();
return true;
} catch (SQLException e) {
Log.d("数据库链接关闭失败!", e);
return false;
}
}
/**
* 复制当前数据核心的数据库到指定的数据库
* 此方法将不会删除当前数据库原有数据
* 此方法可能花费较长的时间
*
* 注意: 当前方法将不会创建表在新的数据库内 需要自行创建数据表
*
* @param db
* 接受数据的数据库核心
* @return 是否转换成功
*/
public boolean copyTo(DataBaseCore db) {
try {
String src = this.dataBaseCore.getConnection().getMetaData().getURL();
String des = db.getConnection().getMetaData().getURL();
Log.i("开始从源 " + src + " 复制数据到 " + des + " ...");
ResultSet rs = this.dataBaseCore.getConnection().getMetaData().getTables(null, null, "%", null);
List<String> tables = new LinkedList<>();
while (rs.next()) {
tables.add(rs.getString("TABLE_NAME"));
}
info("源数据库中有 " + tables.size() + " 张数据表 ...");
rs.close();
int s = 0;
long start = System.currentTimeMillis();
for (String table : tables) {
Log.i("开始复制源数据库中的表 " + table + " ...");
if (table.toLowerCase().startsWith("sqlite_autoindex_")) {
continue;
}
Log.i("清空目标数据库中的表 " + table + " ...");
db.execute("DELETE FROM " + table);
rs = this.dataBaseCore.query("SELECT * FROM " + table);
int n = 0;
String query = "INSERT INTO " + table + " VALUES (";
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
query += "?, ";
}
query = query.substring(0, query.length() - 2) + ")";
Connection con = db.getConnection();
try {
con.setAutoCommit(false);
PreparedStatement ps = con.prepareStatement(query);
long time = System.currentTimeMillis();
while (rs.next()) {
n++;
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
ps.setObject(i, rs.getObject(i));
}
ps.addBatch();
if (n % 100 == 0) {
try {
ps.executeBatch();
con.commit();
} catch (SQLException e) {
info("#====================================================");
info("#数据复制区段(不是ID!) " + (n - 100) + "-" + n + " 出现错误...");
info("#错误信息如下: ");
e.printStackTrace();
info("#====================================================");
}
}
if (System.currentTimeMillis() - time > 500) {
info("已复制 " + n + " 条记录...");
time = System.currentTimeMillis();
}
}
s += n;
ps.executeBatch();
con.commit();
info("数据表 " + table + " 复制完成 共 " + n + " 条记录...");
} catch (Exception e) {
e.printStackTrace();
} finally {
con.setAutoCommit(true);
}
rs.close();
}
info("成功从 " + src + " 复制 " + s + " 条数据到 " + des + " 耗时 " + (System.currentTimeMillis() - start) / 1000 + " 秒...");
db.getConnection().close();
this.dataBaseCore.getConnection().close();
return true;
} catch (SQLException e) {
return false;
}
}
/**
* 创建数据表
*
* @param tableName
* 表名
* @param fields
* 字段参数
* @param Conditions
* -附加值
* @return 运行结果
*/
public boolean createTables(String tableName, KeyValue fields, String Conditions) {
try {
this.dataBaseCore.createTables(tableName, fields, Conditions);
return isTableExists(tableName);
} catch (Exception e) {
sqlerr("创建数据表 " + tableName + " 异常(内部方法)...", e);
return false;
}
}
/**
* 对数据库表中的记录进行删除操作
*
* @param tableName
* 表名
* @param fields
* 删除条件
* @return 受到影响的数据条目
*/
public int dbDelete(String tableName, KeyValue fields) {
String sql = "DELETE FROM `" + tableName + "` WHERE " + fields.toWhereString();
try {
return this.dataBaseCore.update(sql);
} catch (Exception e) {
sqlerr(sql, e);
return 0;
}
}
/**
* 判断数据库某个值是否存在!
*
* @param tableName
* 数据库表名
* @param fields
* 选择条件
* @return 首个符合条件的结果
*/
public boolean dbExist(String tableName, KeyValue fields) {
String sql = "SELECT * FROM " + tableName + " WHERE " + fields.toWhereString();
try {
return this.dataBaseCore.query(sql).next();
} catch (Exception e) {
sqlerr(sql, e);
return false;
}
}
/**
* 对数据库表进行插入操作
*
* @param tabName
* 表名
* @param fields
* 带键值的
* @return 受到影响的数据条目
*/
public int dbInsert(String tabName, KeyValue fields) {
String sql = "INSERT INTO `" + tabName + "` " + fields.toInsertString();
try {
return this.dataBaseCore.update(sql);
} catch (Exception e) {
sqlerr(sql, e);
return 0;
}
}
/**
* 对数据库表进行选择操作!
*
* @param tableName
* 数据库表名
* @param fields
* 读取的字段
* @param selCondition
* 选择条件
* @return 一个含有KeyValue的List列表
*/
public List<KeyValue> dbSelect(String tableName, KeyValue fields, KeyValue selCondition) {
String sql = "SELECT " + fields.toKeys() + " FROM `" + tableName + "`" + (selCondition == null ? "" : " WHERE " + selCondition.toWhereString());
List<KeyValue> kvlist = new ArrayList<>();
try {
ResultSet dbresult = this.dataBaseCore.query(sql);
while (dbresult.next()) {
KeyValue kv = new KeyValue();
for (String col : fields.getKeys()) {
kv.add(col, dbresult.getString(col));
}
kvlist.add(kv);
}
} catch (Exception e) {
sqlerr(sql, e);
}
return kvlist;
}
/**
* 对数据库表进行选择操作!
*
* @param tableName
* 数据库表名
* @param selCondition
* 选择条件
* @param fields
* 读取的字段
* @return 一个含有KeyValue的List列表
*/
public List<KeyValue> dbSelect(String tableName, KeyValue selCondition, String... fields) {
String sql = "SELECT " + getKeys(fields) + " FROM `" + tableName + "`" + (selCondition == null ? "" : " WHERE " + selCondition.toWhereString());
List<KeyValue> kvlist = new ArrayList<>();
try {
ResultSet dbresult = this.dataBaseCore.query(sql);
while (dbresult.next()) {
KeyValue kv = new KeyValue();
for (String col : fields) {
kv.add(col, dbresult.getString(col));
}
kvlist.add(kv);
}
} catch (Exception e) {
sqlerr(sql, e);
}
return kvlist;
}
/**
* 对数据库表进行选择操作!
*
* @param tableName
* 数据库表名
* @param fields
* 字段名
* @param selConditions
* 选择条件
* @return 首个符合条件的结果
*/
public String dbSelectFirst(String tableName, String fields, KeyValue selConditions) {
String sql = "SELECT " + fields + " FROM " + tableName + " WHERE " + selConditions.toWhereString() + " limit 1";
try {
ResultSet dbresult = this.dataBaseCore.query(sql);
if (dbresult.next()) { return dbresult.getString(fields); }
} catch (Exception e) {
sqlerr(sql, e);
}
return null;
}
/**
* 对数据库表中记录进行更新操作
*
* @param tabName
* 表名
* @param fields
* 字段参数
* @param upCondition
* 更新条件
* @return 受到影响的数据条目
*/
public int dbUpdate(String tabName, KeyValue fields, KeyValue upCondition) {
String sql = "UPDATE `" + tabName + "` SET " + fields.toUpdateString() + " WHERE " + upCondition.toWhereString();
try {
return this.dataBaseCore.update(sql);
} catch (Exception e) {
sqlerr(sql, e);
return 0;
}
}
/**
* 获得当前使用的数据库核心
*
* @return 数据库核心
*/
public DataBaseCore getDataBaseCore() {
return this.dataBaseCore;
}
/**
* 字段数组转字符串
*
* @param fields
* 字段数组
* @return 字段字符串
*/
public String getKeys(String... fields) {
StringBuilder sb = new StringBuilder();
for (String string : fields) {
sb.append("`");
sb.append(string);
sb.append("`, ");
}
return sb.toString().substring(0, sb.length() - 2);
}
public boolean isFieldExists(String tableName, KeyValue fields) {
DatabaseMetaData dbm;
ResultSet tables;
try {
dbm = this.dataBaseCore.getConnection().getMetaData();
tables = dbm.getTables(null, null, tableName, null);
if (tables.next()) {
ResultSet f = dbm.getColumns(null, null, tableName, fields.getKeys()[0]);
return f.next();
}
} catch (SQLException e) {
sqlerr("判断 表名:" + tableName + " 字段名:" + fields.getKeys()[0] + " 是否存在时出错!", e);
}
return false;
}
/**
* 判断数据表是否存在
*
* @param tableName
* 表名
* @return 是否存在
*/
public boolean isTableExists(String tableName) {
try {
DatabaseMetaData dbm = this.dataBaseCore.getConnection().getMetaData();
ResultSet tables = dbm.getTables(null, null, tableName, null);
return tables.next();
} catch (SQLException e) {
sqlerr("判断 表名:" + tableName + " 是否存在时出错!", e);
return false;
}
}
/**
* 批量执行SQL语句
*
* @param sqls
* SQL语句列表
*/
public void runSqlList(Collection<String> sqls) {
Connection con = getDataBaseCore().getConnection();
long start = System.currentTimeMillis();
try {
long time = System.currentTimeMillis();
con.setAutoCommit(false);
Statement st = con.createStatement();
int i = 0;
for (String sql : sqls) {
st.addBatch(sql);
i++;
if (i % 100 == 0) {
st.executeBatch();
con.commit();
if (System.currentTimeMillis() - time > 500) {
info("已执行 " + i + " 条语句...");
time = System.currentTimeMillis();
}
}
}
st.executeBatch();
con.commit();
info("执行SQL完毕 总计: " + sqls.size() + " 条 耗时: " + start + "ms!");
} catch (SQLException e) {
try {
con.rollback();
sqlerr("执行SQL数组发生错误 数据已回滚...", e);
} catch (SQLException e1) {
sqlerr("执行SQL数组发生错误 警告! 数据回滚失败...", e1);
}
} finally {
try {
con.setAutoCommit(true);
} catch (SQLException ignored) {
}
}
}
/**
* 输出SQL错误
*
* @param sql
* SQL语句
* @param e
* 错误异常
*/
public void sqlerr(String sql, Exception e) {
info("数据库操作出错: " + e.getMessage());
info("SQL查询语句: " + sql);
Log.d(this.getClass().getName());
Log.d(e);
}
/**
* 测试数据库连接
*
* @return 是否连接成功
*/
public boolean testConnect() {
return this.dataBaseCore.getConnection() != null;
}
private void info(String info) {
Log.i(info);
}
public static class DataBaseParse implements Parse<DataBase> {
public DataBaseParse() {
InjectParse.register(DataBase.class, this);
}
@Override
public DataBase parse(ConfigurationSection config, String path) {
return DataBase.create(P.instance, config.getConfigurationSection(path));
}
}
}