面试题答案
一键面试1. 数据库表结构设计
创建一个名为 file_uploads
的表,用于存储文件上传的元数据。表结构如下:
CREATE TABLE file_uploads (
id INT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255) NOT NULL,
file_size BIGINT NOT NULL,
upload_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
id
:自增主键,唯一标识每条记录。file_name
:存储上传文件的文件名,VARCHAR
类型,最大长度255字符。file_size
:存储文件大小,BIGINT
类型,以字节为单位。upload_time
:存储文件上传的时间,TIMESTAMP
类型,默认值为当前时间。
2. 文件上传成功后插入元数据到数据库
假设使用 multer
中间件进行文件上传,以下是在文件上传成功后将元数据插入数据库的代码示例:
const express = require('express');
const multer = require('multer');
const mysql = require('mysql2');
const app = express();
const upload = multer({ dest: 'uploads/' });
// 创建数据库连接
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'your_database'
});
connection.connect();
app.post('/upload', upload.single('file'), (req, res) => {
const { originalname, size } = req.file;
const query = 'INSERT INTO file_uploads (file_name, file_size) VALUES (?,?)';
connection.query(query, [originalname, size], (error, results, fields) => {
if (error) {
console.error('Error inserting data into database:', error);
return res.status(500).send('Error inserting data into database');
}
res.send('File uploaded and metadata saved successfully');
});
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
- 首先,引入
express
、multer
和mysql2
模块。 - 使用
multer
中间件处理文件上传,并指定上传文件的存储目录为uploads/
。 - 创建 MySQL 数据库连接。
- 在
/upload
路由中,当文件上传成功后,从req.file
对象中获取文件名(originalname
)和文件大小(size
)。 - 使用
connection.query
方法执行 SQL 插入语句,将文件名和文件大小插入到file_uploads
表中。
3. 事务处理问题及解决方案
问题:
- 可能会出现文件上传成功,但在插入数据库元数据时失败的情况。这种情况下,会导致文件已上传但数据库中没有对应的元数据记录,数据不一致。
解决方案:
- 使用数据库事务来确保文件上传和元数据插入操作的原子性。即要么两者都成功,要么都失败。 以下是使用事务处理的代码示例:
app.post('/upload', upload.single('file'), (req, res) => {
const { originalname, size } = req.file;
connection.beginTransaction((err) => {
if (err) {
console.error('Error starting transaction:', err);
return res.status(500).send('Error starting transaction');
}
const query = 'INSERT INTO file_uploads (file_name, file_size) VALUES (?,?)';
connection.query(query, [originalname, size], (error, results, fields) => {
if (error) {
connection.rollback(() => {
console.error('Error inserting data into database, rolling back:', error);
return res.status(500).send('Error inserting data into database, rolling back');
});
} else {
connection.commit((err) => {
if (err) {
console.error('Error committing transaction:', err);
connection.rollback(() => {
console.error('Rolling back due to commit error:', err);
return res.status(500).send('Error committing transaction, rolling back');
});
} else {
res.send('File uploaded and metadata saved successfully');
}
});
}
});
});
});
- 使用
connection.beginTransaction
方法开始一个事务。 - 如果在插入数据库操作中出现错误,调用
connection.rollback
方法回滚事务,撤销之前的操作。 - 如果插入操作成功,调用
connection.commit
方法提交事务,确保文件上传和元数据插入操作都持久化到数据库中。如果提交过程中出现错误,同样回滚事务。