You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
9.7 KiB
263 lines
9.7 KiB
// 数据库服务
|
|
const mysql = require('mysql2/promise');
|
|
const config = require('../config/config');
|
|
|
|
class DatabaseService {
|
|
constructor() {
|
|
this.connection = null;
|
|
}
|
|
|
|
// 连接数据库
|
|
async connect() {
|
|
try {
|
|
this.connection = await mysql.createConnection({
|
|
host: config.db.host,
|
|
port: config.db.port,
|
|
user: config.db.user,
|
|
password: config.db.password,
|
|
database: config.db.database
|
|
});
|
|
console.log('数据库连接成功');
|
|
return this.connection;
|
|
} catch (error) {
|
|
console.error('数据库连接失败:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 断开数据库连接
|
|
async disconnect() {
|
|
if (this.connection) {
|
|
await this.connection.end();
|
|
console.log('数据库连接已断开');
|
|
}
|
|
}
|
|
|
|
// 查询需要同步的数据
|
|
async getAllSyncData() {
|
|
try {
|
|
// 根据配置决定是查询所有数据还是仅未同步数据
|
|
let usersQuery = `SELECT ${config.tables.users.fields.id},
|
|
${config.tables.users.fields.userId},
|
|
${config.tables.users.fields.phoneNumber},
|
|
${config.tables.users.fields.type},
|
|
${config.tables.users.fields.authorizedRegion},
|
|
${config.tables.users.fields.nickName},
|
|
jiandaoyun_record_id
|
|
FROM ${config.tables.users.name}`;
|
|
|
|
// 如果是增量同步,查询未同步的数据以及有收藏产品的用户
|
|
if (config.sync.incremental) {
|
|
usersQuery += ` WHERE ${config.sync.statusField} = ${config.sync.unsyncedValue}
|
|
OR EXISTS (SELECT 1 FROM ${config.tables.favorites.name}
|
|
WHERE ${config.tables.favorites.fields.userPhone} = ${config.tables.users.fields.phoneNumber})`;
|
|
console.log('启用增量同步模式,查询未同步数据及有收藏产品的用户');
|
|
} else {
|
|
console.log('启用全量同步模式,查询所有数据');
|
|
}
|
|
|
|
// 添加DISTINCT确保只返回唯一的用户数据
|
|
usersQuery = usersQuery.replace('SELECT', 'SELECT DISTINCT');
|
|
|
|
console.log('执行用户查询:', usersQuery);
|
|
const [users] = await this.connection.execute(usersQuery);
|
|
console.log(`查询结果: 共找到 ${users.length} 条需要同步的用户数据`);
|
|
|
|
const syncData = [];
|
|
|
|
// 为每个用户查询关联数据
|
|
for (const user of users) {
|
|
const userId = user[config.tables.users.fields.userId];
|
|
const phoneNumber = user[config.tables.users.fields.phoneNumber];
|
|
const jiandaoyunRecordId = user.jiandaoyun_record_id;
|
|
|
|
// 查询负责人信息(usermanagements表)
|
|
const [userManagements] = await this.connection.execute(
|
|
`SELECT ${config.tables.userManagements.fields.userName}
|
|
FROM ${config.tables.userManagements.name}
|
|
WHERE ${config.tables.userManagements.fields.userId} = ?`,
|
|
[userId]
|
|
);
|
|
|
|
// 查询用户收藏的产品(favorites表)
|
|
const [favorites] = await this.connection.execute(
|
|
`SELECT ${config.tables.favorites.fields.productId}
|
|
FROM ${config.tables.favorites.name}
|
|
WHERE ${config.tables.favorites.fields.userPhone} = ?`,
|
|
[phoneNumber]
|
|
);
|
|
|
|
// 查询产品详情(products表)
|
|
let products = [];
|
|
if (favorites.length > 0) {
|
|
const productIds = favorites.map(fav => fav[config.tables.favorites.fields.productId]);
|
|
// 构建动态占位符字符串,用于处理IN查询的数组参数
|
|
const placeholders = productIds.map(() => '?').join(',');
|
|
const [productsResult] = await this.connection.execute(
|
|
`SELECT ${config.tables.products.fields.productName},
|
|
${config.tables.products.fields.specification},
|
|
${config.tables.products.fields.quantity},
|
|
${config.tables.products.fields.grossWeight},
|
|
${config.tables.products.fields.yolk}
|
|
FROM ${config.tables.products.name}
|
|
WHERE ${config.tables.products.fields.productId} IN (${placeholders})`,
|
|
productIds
|
|
);
|
|
products = productsResult;
|
|
|
|
// 如果用户有收藏商品,无论当前同步状态如何,都将其重置为未同步状态
|
|
// 这样可以确保有新收藏商品的用户数据会被重新同步到简道云
|
|
await this.connection.execute(
|
|
`UPDATE ${config.tables.users.name}
|
|
SET ${config.sync.statusField} = ?
|
|
WHERE ${config.tables.users.fields.userId} = ?`,
|
|
[config.sync.unsyncedValue, userId]
|
|
);
|
|
console.log(`用户 ${userId} 有收藏商品,同步状态已重置为未同步`);
|
|
}
|
|
|
|
syncData.push({
|
|
user,
|
|
userManagement: userManagements[0] || {},
|
|
products,
|
|
userId: userId // 保存用户ID,用于同步后更新状态
|
|
});
|
|
}
|
|
|
|
return syncData;
|
|
} catch (error) {
|
|
console.error('查询数据失败:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 获取一条测试数据用于API测试
|
|
async getTestData() {
|
|
try {
|
|
// 获取一条用户数据
|
|
const [users] = await this.connection.execute(
|
|
`SELECT ${config.tables.users.fields.id},
|
|
${config.tables.users.fields.userId},
|
|
${config.tables.users.fields.company},
|
|
${config.tables.users.fields.name},
|
|
${config.tables.users.fields.phoneNumber},
|
|
${config.tables.users.fields.type},
|
|
${config.tables.users.fields.city}
|
|
FROM ${config.tables.users.name} LIMIT 1`
|
|
);
|
|
|
|
if (users.length === 0) {
|
|
console.error('没有找到用户数据');
|
|
return null;
|
|
}
|
|
|
|
const user = users[0];
|
|
const userId = user[config.tables.users.fields.id];
|
|
|
|
// 获取该用户的购物车数据
|
|
const [cartItems] = await this.connection.execute(
|
|
`SELECT ${config.tables.cartItems.fields.productName},
|
|
${config.tables.cartItems.fields.specification},
|
|
${config.tables.cartItems.fields.quantity},
|
|
${config.tables.cartItems.fields.yolk}
|
|
FROM ${config.tables.cartItems.name}
|
|
WHERE ${config.tables.cartItems.fields.userId} = ?`,
|
|
[userId]
|
|
);
|
|
|
|
// 获取该用户的产品数据
|
|
const [products] = await this.connection.execute(
|
|
`SELECT ${config.tables.products.fields.productName},
|
|
${config.tables.products.fields.specification},
|
|
${config.tables.products.fields.quantity},
|
|
${config.tables.products.fields.yolk}
|
|
FROM ${config.tables.products.name}
|
|
WHERE ${config.tables.products.fields.sellerId} = ?`,
|
|
[userId]
|
|
);
|
|
|
|
return {
|
|
user,
|
|
cartItems,
|
|
products
|
|
};
|
|
} catch (error) {
|
|
console.error('获取测试数据失败:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 更新数据同步状态
|
|
async updateSyncStatus(userId, synced) {
|
|
try {
|
|
const statusValue = synced ? config.sync.syncedValue : config.sync.unsyncedValue;
|
|
const now = new Date();
|
|
|
|
await this.connection.execute(
|
|
`UPDATE ${config.tables.users.name}
|
|
SET ${config.sync.statusField} = ?, ${config.sync.timeField} = ?
|
|
WHERE ${config.tables.users.fields.userId} = ?`,
|
|
[statusValue, now, userId]
|
|
);
|
|
|
|
console.log(`用户 ${userId} 的同步状态已更新为: ${synced ? '已同步' : '未同步'}`);
|
|
} catch (error) {
|
|
console.error(`更新用户 ${userId} 同步状态失败:`, error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 测试数据库连接和表结构
|
|
async testDatabaseConnection() {
|
|
try {
|
|
// 测试连接
|
|
await this.connect();
|
|
|
|
// 查询表结构
|
|
const tables = [config.tables.users.name, config.tables.cartItems.name, config.tables.products.name];
|
|
|
|
for (const table of tables) {
|
|
console.log(`\n--- 表 ${table} 结构 ---`);
|
|
const [columns] = await this.connection.execute(`DESCRIBE ${table}`);
|
|
columns.forEach(column => {
|
|
console.log(`${column.Field}: ${column.Type} ${column.Null === 'YES' ? '(允许为空)' : '(不允许为空)'} ${column.Key === 'PRI' ? '(主键)' : ''}`);
|
|
});
|
|
}
|
|
|
|
// 查询示例数据
|
|
console.log(`\n--- 示例数据 ---`);
|
|
const [usersSample] = await this.connection.execute(`SELECT * FROM ${config.tables.users.name} LIMIT 1`);
|
|
if (usersSample.length > 0) {
|
|
console.log('用户表示例数据:', usersSample[0]);
|
|
|
|
const userId = usersSample[0][config.tables.users.fields.id];
|
|
const [cartItemsSample] = await this.connection.execute(
|
|
`SELECT * FROM ${config.tables.cartItems.name} WHERE ${config.tables.cartItems.fields.userId} = ? LIMIT 1`,
|
|
[userId]
|
|
);
|
|
if (cartItemsSample.length > 0) {
|
|
console.log('购物车表示例数据:', cartItemsSample[0]);
|
|
}
|
|
|
|
const [productsSample] = await this.connection.execute(
|
|
`SELECT * FROM ${config.tables.products.name} WHERE ${config.tables.products.fields.sellerId} = ? LIMIT 1`,
|
|
[userId]
|
|
);
|
|
if (productsSample.length > 0) {
|
|
console.log('产品表示例数据:', productsSample[0]);
|
|
}
|
|
}
|
|
|
|
await this.disconnect();
|
|
return true;
|
|
} catch (error) {
|
|
console.error('数据库测试失败:', error.message);
|
|
if (this.connection) {
|
|
await this.disconnect();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new DatabaseService();
|
|
|