本文目录导读:

我来提供几个基于数据库实现的完整案例,涵盖不同场景和技术栈。
图书管理系统
数据库设计
-- 创建数据库
CREATE DATABASE library_system;
USE library_system;
-- 图书表
CREATE TABLE books (
book_id INT PRIMARY KEY AUTO_INCREMENT,
isbn VARCHAR(20) UNIQUE NOT NULL,VARCHAR(200) NOT NULL,
author VARCHAR(100) NOT NULL,
publisher VARCHAR(100),
publish_date DATE,
category VARCHAR(50),
total_count INT DEFAULT 1,
available_count INT DEFAULT 1,
location VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 读者表
CREATE TABLE readers (
reader_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
id_card VARCHAR(18) UNIQUE NOT NULL,
phone VARCHAR(20),
email VARCHAR(100),
address VARCHAR(200),
level VARCHAR(20) DEFAULT '普通读者',
max_borrow INT DEFAULT 5,
status VARCHAR(20) DEFAULT '正常',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 借阅记录表
CREATE TABLE borrow_records (
record_id INT PRIMARY KEY AUTO_INCREMENT,
book_id INT NOT NULL,
reader_id INT NOT NULL,
borrow_date DATE NOT NULL,
due_date DATE NOT NULL,
return_date DATE,
status VARCHAR(20) DEFAULT '借出',
renew_count INT DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES books(book_id),
FOREIGN KEY (reader_id) REFERENCES readers(reader_id)
);
-- 罚款记录表
CREATE TABLE fines (
fine_id INT PRIMARY KEY AUTO_INCREMENT,
record_id INT NOT NULL,
reader_id INT NOT NULL,
amount DECIMAL(10,2),
reason VARCHAR(200),
status VARCHAR(20) DEFAULT '未缴纳',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (record_id) REFERENCES borrow_records(record_id),
FOREIGN KEY (reader_id) REFERENCES readers(reader_id)
);
核心功能实现(Python + MySQL)
import mysql.connector
from datetime import datetime, timedelta
class LibrarySystem:
def __init__(self, host='localhost', user='root', password='', database='library_system'):
self.conn = mysql.connector.connect(
host=host,
user=user,
password=password,
database=database
)
self.cursor = self.conn.cursor(dictionary=True)
# 借书功能
def borrow_book(self, reader_id, book_id):
try:
# 开启事务
self.conn.start_transaction()
# 检查读者状态和借阅数量
self.cursor.execute("""
SELECT status, max_borrow FROM readers WHERE reader_id = %s
""", (reader_id,))
reader = self.cursor.fetchone()
if not reader or reader['status'] != '正常':
raise Exception("读者状态异常")
# 检查图书是否可借
self.cursor.execute("""
SELECT available_count FROM books
WHERE book_id = %s AND available_count > 0
""", (book_id,))
book = self.cursor.fetchone()
if not book:
raise Exception("图书不可借")
# 检查当前借阅数量
self.cursor.execute("""
SELECT COUNT(*) as count FROM borrow_records
WHERE reader_id = %s AND status = '借出'
""", (reader_id,))
current_count = self.cursor.fetchone()['count']
if current_count >= reader['max_borrow']:
raise Exception("已达到最大借阅数量")
# 创建借阅记录
borrow_date = datetime.now().date()
due_date = borrow_date + timedelta(days=30)
self.cursor.execute("""
INSERT INTO borrow_records (book_id, reader_id, borrow_date, due_date)
VALUES (%s, %s, %s, %s)
""", (book_id, reader_id, borrow_date, due_date))
# 更新图书库存
self.cursor.execute("""
UPDATE books SET available_count = available_count - 1
WHERE book_id = %s
""", (book_id,))
self.conn.commit()
return {"success": True, "message": "借书成功"}
except Exception as e:
self.conn.rollback()
return {"success": False, "message": str(e)}
# 还书功能
def return_book(self, record_id):
try:
self.conn.start_transaction()
# 更新借阅记录
return_date = datetime.now().date()
self.cursor.execute("""
UPDATE borrow_records
SET return_date = %s, status = '已还'
WHERE record_id = %s AND status = '借出'
""", (return_date, record_id))
if self.cursor.rowcount == 0:
raise Exception("借阅记录不存在或已归还")
# 获取图书ID
self.cursor.execute("""
SELECT book_id, due_date FROM borrow_records WHERE record_id = %s
""", (record_id,))
record = self.cursor.fetchone()
# 检查是否逾期
if return_date > record['due_date']:
days = (return_date - record['due_date']).days
fine_amount = days * 0.5 # 每天0.5元罚款
self.cursor.execute("""
INSERT INTO fines (record_id, reader_id, amount, reason)
SELECT %s, reader_id, %s, '逾期归还'
FROM borrow_records WHERE record_id = %s
""", (record_id, fine_amount, record_id))
message = f"还书成功,产生逾期罚款 {fine_amount} 元"
else:
message = "还书成功"
# 更新图书库存
self.cursor.execute("""
UPDATE books SET available_count = available_count + 1
WHERE book_id = %s
""", (record['book_id'],))
self.conn.commit()
return {"success": True, "message": message}
except Exception as e:
self.conn.rollback()
return {"success": False, "message": str(e)}
# 查询图书
def search_books(self, keyword, category=None):
query = """
SELECT b.*,
(b.total_count - b.available_count) as borrowed_count
FROM books b
WHERE b.title LIKE %s OR b.author LIKE %s OR b.isbn LIKE %s
"""
params = [f'%{keyword}%'] * 3
if category:
query += " AND b.category = %s"
params.append(category)
self.cursor.execute(query, params)
return self.cursor.fetchall()
# 获取逾期未还图书
def get_overdue_books(self):
self.cursor.execute("""
SELECT br.record_id, r.name as reader_name, b.title as book_title,
br.due_date, DATEDIFF(CURDATE(), br.due_date) as overdue_days
FROM borrow_records br
JOIN readers r ON br.reader_id = r.reader_id
JOIN books b ON br.book_id = b.book_id
WHERE br.status = '借出' AND br.due_date < CURDATE()
""")
return self.cursor.fetchall()
电商订单系统
数据库设计
CREATE DATABASE ecommerce;
USE ecommerce;
-- 用户表
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP
);
-- 商品分类表
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
parent_id INT DEFAULT NULL,
name VARCHAR(50) NOT NULL,
description TEXT,
FOREIGN KEY (parent_id) REFERENCES categories(category_id)
);
-- 商品表
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
category_id INT,
name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10,2) NOT NULL,
stock INT DEFAULT 0,
sales INT DEFAULT 0,
image_url VARCHAR(500),
status VARCHAR(20) DEFAULT '上架',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(category_id)
);
-- 购物车表
CREATE TABLE cart (
cart_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT DEFAULT 1,
add_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_cart_item (user_id, product_id),
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(30) UNIQUE NOT NULL,
user_id INT NOT NULL,
total_amount DECIMAL(12,2) NOT NULL,
pay_amount DECIMAL(12,2) NOT NULL,
freight_amount DECIMAL(10,2),
status VARCHAR(20) DEFAULT '待支付',
address VARCHAR(200) NOT NULL,
receiver VARCHAR(50) NOT NULL,
phone VARCHAR(20) NOT NULL,
pay_time DATETIME,
delivery_time DATETIME,
receive_time DATETIME,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
-- 订单明细表
CREATE TABLE order_items (
item_id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
product_name VARCHAR(200),
product_image VARCHAR(500),
price DECIMAL(10,2),
quantity INT,
total_price DECIMAL(10,2),
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
核心功能实现(Java + JDBC)
public class OrderService {
// 创建订单
public boolean createOrder(Order order, List<CartItem> cartItems) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 生成订单号
String orderNo = generateOrderNo(conn);
// 计算订单金额
double totalAmount = 0;
for (CartItem item : cartItems) {
// 检查库存
if (!checkStock(conn, item.getProductId(), item.getQuantity())) {
throw new RuntimeException("商品库存不足:" + item.getProductName());
}
totalAmount += item.getPrice() * item.getQuantity();
}
// 插入订单
String sql = "INSERT INTO orders (order_no, user_id, total_amount, pay_amount, " +
"address, receiver, phone) VALUES (?, ?, ?, ?, ?, ?, ?)";
ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, orderNo);
ps.setInt(2, order.getUserId());
ps.setDouble(3, totalAmount);
ps.setDouble(4, totalAmount);
ps.setString(5, order.getAddress());
ps.setString(6, order.getReceiver());
ps.setString(7, order.getPhone());
ps.executeUpdate();
// 获取订单ID
rs = ps.getGeneratedKeys();
int orderId = 0;
if (rs.next()) {
orderId = rs.getInt(1);
}
// 插入订单明细并更新库存
for (CartItem item : cartItems) {
insertOrderItem(conn, orderId, item);
updateStock(conn, item.getProductId(), item.getQuantity());
}
// 清空购物车
clearCart(conn, order.getUserId());
conn.commit();
return true;
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
throw new RuntimeException("创建订单失败:" + e.getMessage());
} finally {
DBUtil.close(conn, ps, rs);
}
}
// 取消订单
public boolean cancelOrder(String orderNo, int userId) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 查询订单状态
String querySql = "SELECT order_id, status FROM orders WHERE order_no = ? AND user_id = ?";
ps = conn.prepareStatement(querySql);
ps.setString(1, orderNo);
ps.setInt(2, userId);
rs = ps.executeQuery();
if (!rs.next()) {
throw new RuntimeException("订单不存在");
}
String status = rs.getString("status");
if (!"待支付".equals(status)) {
throw new RuntimeException("当前订单状态不能取消");
}
int orderId = rs.getInt("order_id");
// 查询订单明细,恢复库存
String itemsSql = "SELECT product_id, quantity FROM order_items WHERE order_id = ?";
ps = conn.prepareStatement(itemsSql);
ps.setInt(1, orderId);
rs = ps.executeQuery();
List<ItemInfo> items = new ArrayList<>();
while (rs.next()) {
ItemInfo item = new ItemInfo();
item.setProductId(rs.getInt("product_id"));
item.setQuantity(rs.getInt("quantity"));
items.add(item);
}
// 恢复库存
for (ItemInfo item : items) {
String updateStockSql = "UPDATE products SET stock = stock + ? WHERE product_id = ?";
ps = conn.prepareStatement(updateStockSql);
ps.setInt(1, item.getQuantity());
ps.setInt(2, item.getProductId());
ps.executeUpdate();
}
// 更新订单状态
String updateOrderSql = "UPDATE orders SET status = '已取消' WHERE order_id = ?";
ps = conn.prepareStatement(updateOrderSql);
ps.setInt(1, orderId);
ps.executeUpdate();
conn.commit();
return true;
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
throw new RuntimeException("取消订单失败:" + e.getMessage());
} finally {
DBUtil.close(conn, ps, rs);
}
}
// 支付订单
public boolean payOrder(String orderNo, int userId, PaymentType paymentType) {
// 使用事务和乐观锁实现
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 使用乐观锁防止并发问题
String sql = "UPDATE orders SET status = '已支付', pay_time = NOW() " +
"WHERE order_no = ? AND user_id = ? AND status = '待支付'";
ps = conn.prepareStatement(sql);
ps.setString(1, orderNo);
ps.setInt(2, userId);
int rows = ps.executeUpdate();
if (rows == 0) {
throw new RuntimeException("订单状态已变化,请刷新后重试");
}
conn.commit();
return true;
} catch (Exception e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
throw new RuntimeException("支付失败:" + e.getMessage());
} finally {
DBUtil.close(conn, ps, rs);
}
}
// 查询用户订单列表(分页)
public PageResult<OrderVO> queryOrders(int userId, int pageNum, int pageSize, String status) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
// 构建查询条件
StringBuilder whereSql = new StringBuilder(" WHERE user_id = ?");
List<Object> params = new ArrayList<>();
params.add(userId);
if (status != null && !"".equals(status)) {
whereSql.append(" AND status = ?");
params.add(status);
}
// 查询总数
String countSql = "SELECT COUNT(*) FROM orders" + whereSql;
ps = conn.prepareStatement(countSql);
setParams(ps, params);
rs = ps.executeQuery();
int total = 0;
if (rs.next()) {
total = rs.getInt(1);
}
// 分页查询
String listSql = "SELECT * FROM orders" + whereSql +
" ORDER BY create_time DESC LIMIT ?, ?";
ps = conn.prepareStatement(listSql);
setParams(ps, params);
ps.setInt(params.size() + 1, (pageNum - 1) * pageSize);
ps.setInt(params.size() + 2, pageSize);
rs = ps.executeQuery();
List<OrderVO> orders = new ArrayList<>();
while (rs.next()) {
OrderVO vo = convertToVO(rs);
// 获取订单明细
vo.setItems(queryOrderItems(conn, rs.getInt("order_id")));
orders.add(vo);
}
PageResult<OrderVO> pageResult = new PageResult<>();
pageResult.setList(orders);
pageResult.setTotal(total);
pageResult.setPageNum(pageNum);
pageResult.setPageSize(pageSize);
pageResult.setTotalPage((int) Math.ceil((double) total / pageSize));
return pageResult;
} catch (Exception e) {
throw new RuntimeException("查询订单失败:" + e.getMessage());
} finally {
DBUtil.close(conn, ps, rs);
}
}
// 商品销量统计
public List<ProductStat> getTopProducts(int topN) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "SELECT p.product_id, p.name, p.sales, " +
"SUM(oi.quantity) as total_sold " +
"FROM products p " +
"LEFT JOIN order_items oi ON p.product_id = oi.product_id " +
"LEFT JOIN orders o ON oi.order_id = o.order_id " +
"AND o.status IN ('已支付', '已发货', '已完成') " +
"GROUP BY p.product_id, p.name, p.sales " +
"ORDER BY total_sold DESC LIMIT ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, topN);
rs = ps.executeQuery();
List<ProductStat> stats = new ArrayList<>();
while (rs.next()) {
ProductStat stat = new ProductStat();
stat.setProductId(rs.getInt("product_id"));
stat.setProductName(rs.getString("name"));
stat.setTotalSales(rs.getInt("total_sold"));
stats.add(stat);
}
return stats;
} catch (Exception e) {
throw new RuntimeException("统计销量失败:" + e.getMessage());
} finally {
DBUtil.close(conn, ps, rs);
}
}
}
员工考勤系统
数据库设计
CREATE DATABASE attendance_system;
USE attendance_system;
-- 部门表
CREATE TABLE departments (
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL,
manager_id INT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_no VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
gender CHAR(2),
birth_date DATE,
phone VARCHAR(20),
email VARCHAR(100),
dept_id INT,
position VARCHAR(50),
hire_date DATE,
salary DECIMAL(10,2),
status VARCHAR(20) DEFAULT '在职',
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);
-- 考勤记录表
CREATE TABLE attendance_records (
record_id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT NOT NULL,
work_date DATE NOT NULL,
check_in_time DATETIME,
check_out_time DATETIME,
status VARCHAR(20) DEFAULT '正常',
late_minutes INT DEFAULT 0,
early_minutes INT DEFAULT 0,
overtime_hours DECIMAL(4,1) DEFAULT 0,
remark VARCHAR(200),
FOREIGN KEY (emp_id) REFERENCES employees(emp_id),
UNIQUE KEY unique_attendance (emp_id, work_date)
);
-- 请假表
CREATE TABLE leave_requests (
leave_id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT NOT NULL,
leave_type VARCHAR(20) NOT NULL, -- 年假/事假/病假/调休
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
hours DECIMAL(4,1),
reason TEXT,
status VARCHAR(20) DEFAULT '待审批',
approver_id INT,
approve_time DATETIME,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (emp_id) REFERENCES employees(emp_id),
FOREIGN KEY (approver_id) REFERENCES employees(emp_id)
);
-- 加班申请
CREATE TABLE overtime_requests (
overtime_id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT NOT NULL,
overtime_date DATE NOT NULL,
start_time TIME,
end_time TIME,
hours DECIMAL(4,1),
reason VARCHAR(200),
status VARCHAR(20) DEFAULT '待审批',
approver_id INT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
核心功能实现(Node.js + MySQL)
const mysql = require('mysql2/promise');
const moment = require('moment');
class AttendanceService {
constructor() {
this.pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'attendance_system',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
}
// 签到
async checkIn(empId) {
const connection = await this.pool.getConnection();
try {
await connection.beginTransaction();
const now = moment();
const today = now.format('YYYY-MM-DD');
const time = now.format('HH:mm:ss');
// 检查员工是否在职
const [empResult] = await connection.execute(
'SELECT * FROM employees WHERE emp_id = ? AND status = "在职"',
[empId]
);
if (empResult.length === 0) {
throw new Error('员工不存在或不在职');
}
// 检查是否已签到
const [attResult] = await connection.execute(
'SELECT * FROM attendance_records WHERE emp_id = ? AND work_date = ?',
[empId, today]
);
if (attResult.length > 0) {
if (attResult[0].check_in_time) {
throw new Error('今天已经签到过了');
}
}
// 判断是否迟到(假设9:00上班)
const standardTime = moment(`${today} 09:00:00`);
const lateMinutes = now.diff(standardTime, 'minutes');
let status = '正常';
if (lateMinutes > 0) {
status = '迟到';
}
// 插入或更新考勤记录
const sql = `
INSERT INTO attendance_records (emp_id, work_date, check_in_time, status, late_minutes)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
check_in_time = VALUES(check_in_time),
status = VALUES(status),
late_minutes = VALUES(late_minutes)
`;
await connection.execute(sql, [
empId,
today,
now.format('YYYY-MM-DD HH:mm:ss'),
status,
lateMinutes > 0 ? lateMinutes : 0
]);
// 更新employee的今日打卡状态(可选)
await connection.commit();
return {
success: true,
data: {
empId,
checkInTime: now.format('YYYY-MM-DD HH:mm:ss'),
status,
lateMinutes: lateMinutes > 0 ? lateMinutes : 0
}
};
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
}
// 签退
async checkOut(empId) {
const connection = await this.pool.getConnection();
try {
await connection.beginTransaction();
const now = moment();
const today = now.format('YYYY-MM-DD');
// 检查是否有签到记录
const [attResult] = await connection.execute(
'SELECT * FROM attendance_records WHERE emp_id = ? AND work_date = ?',
[empId, today]
);
if (attResult.length === 0 || !attResult[0].check_in_time) {
throw new Error('请先签到');
}
if (attResult[0].check_out_time) {
throw new Error('今天已经签退过了');
}
// 判断是否早退(假设18:00下班)
const checkoutTime = moment(`${today} 18:00:00`);
const earlyMinutes = checkoutTime.diff(now, 'minutes');
let status = attResult[0].status;
if (earlyMinutes > 0) {
status = '早退';
if (attResult[0].status === '正常') {
status = '早退';
} else {
status = '迟到早退';
}
}
// 计算加班时长
let overtimeHours = 0;
if (now.isAfter(checkoutTime)) {
overtimeHours = parseFloat(now.diff(checkoutTime, 'hours', true).toFixed(1));
}
const updateSql = `
UPDATE attendance_records
SET check_out_time = ?, status = ?, early_minutes = ?, overtime_hours = ?
WHERE emp_id = ? AND work_date = ?
`;
await connection.execute(updateSql, [
now.format('YYYY-MM-DD HH:mm:ss'),
status,
earlyMinutes > 0 ? earlyMinutes : 0,
overtimeHours,
empId,
today
]);
await connection.commit();
return {
success: true,
data: {
empId,
checkOutTime: now.format('YYYY-MM-DD HH:mm:ss'),
status,
earlyMinutes: earlyMinutes > 0 ? earlyMinutes : 0,
overtimeHours
}
};
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
}
// 申请请假
async requestLeave(leaveData) {
const connection = await this.pool.getConnection();
try {
await connection.beginTransaction();
const { empId, leaveType, startTime, endTime, reason } = leaveData;
// 检查请假时间是否有效
if (new Date(endTime) <= new Date(startTime)) {
throw new Error('请假结束时间必须大于开始时间');
}
// 计算请假小时数
const hours = moment(endTime).diff(moment(startTime), 'hours', true);
if (hours <= 0) {
throw new Error('请假时长必须大于0');
}
// 检查是否有重叠的请假
const [overlapResult] = await connection.execute(
`SELECT * FROM leave_requests
WHERE emp_id = ?
AND status = '已批准'
AND start_time < ?
AND end_time > ?`,
[empId, endTime, startTime]
);
if (overlapResult.length > 0) {
throw new Error('与已有的请假时间冲突');
}
// 检查是否有签到记录(请假当天不能签到)
const leaveDates = this.getDatesBetween(startTime, endTime);
for (const date of leaveDates) {
const [attResult] = await connection.execute(
'SELECT * FROM attendance_records WHERE emp_id = ? AND work_date = ?',
[empId, date]
);
// 可以在这里处理已有签到的日期
}
// 插入请假记录
const insertSql = `
INSERT INTO leave_requests (emp_id, leave_type, start_time, end_time, hours, reason)
VALUES (?, ?, ?, ?, ?, ?)
`;
await connection.execute(insertSql, [
empId,
leaveType,
startTime,
endTime,
parseFloat(hours.toFixed(1)),
reason
]);
await connection.commit();
return {
success: true,
message: '请假申请已提交'
};
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
}
// 查询员工考勤统计
async getAttendanceStats(empId, month) {
const connection = await this.pool.getConnection();
try {
const startDate = moment(month + '-01');
const endDate = startDate.clone().endOf('month');
const sql = `
SELECT
COUNT(DISTINCT work_date) as total_days,
SUM(CASE WHEN status = '正常' THEN 1 ELSE 0 END) as normal_days,
SUM(CASE WHEN status = '迟到' THEN 1 ELSE 0 END) as late_days,
SUM(CASE WHEN status = '早退' THEN 1 ELSE 0 END) as early_days,
SUM(CASE WHEN status = '迟到早退' THEN 1 ELSE 0 END) as late_early_days,
SUM(late_minutes) as total_late_minutes,
SUM(early_minutes) as total_early_minutes,
SUM(overtime_hours) as total_overtime_hours
FROM attendance_records
WHERE emp_id = ? AND work_date BETWEEN ? AND ?
`;
const [rows] = await connection.execute(sql, [
empId,
startDate.format('YYYY-MM-DD'),
endDate.format('YYYY-MM-DD')
]);
// 查询请假记录
const [leaveRows] = await connection.execute(
`SELECT
leave_type,
COUNT(*) as leave_count,
SUM(hours) as total_hours
FROM leave_requests
WHERE emp_id = ?
AND status = '已批准'
AND start_time BETWEEN ? AND ?
GROUP BY leave_type`,
[empId, startDate.format('YYYY-MM-DD'), endDate.format('YYYY-MM-DD')]
);
return {
success: true,
data: {
month: month,
stats: rows[0],
leaves: leaveRows
}
};
} catch (error) {
throw error;
} finally {
connection.release();
}
}
// 生成考勤报表
async generateMonthlyReport(deptId, month) {
const connection = await this.pool.getConnection();
try {
const startDate = moment(month + '-01').format('YYYY-MM-DD');
const endDate = moment(month).endOf('month').format('YYYY-MM-DD');
const sql = `
SELECT
e.emp_id,
e.emp_no,
e.name,
e.position,
d.dept_name,
COUNT(DISTINCT a.work_date) as work_days,
SUM(CASE WHEN a.status = '正常' THEN 1 ELSE 0 END) as normal_days,
SUM(CASE WHEN a.status = '迟到' THEN 1 ELSE 0 END) as late_count,
SUM(CASE WHEN a.status = '早退' THEN 1 ELSE 0 END) as early_count,
SUM(CASE WHEN a.status = '请假' THEN 1 ELSE 0 END) as leave_days,
SUM(a.late_minutes) as total_late_minutes,
SUM(a.overtime_hours) as total_overtime_hours,
AVG(a.late_minutes) as avg_late_minutes
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
LEFT JOIN attendance_records a ON e.emp_id = a.emp_id
AND a.work_date BETWEEN ? AND ?
WHERE e.status = '在职'
AND (e.dept_id = ? OR ? IS NULL)
GROUP BY e.emp_id, e.emp_no, e.name, e.position, d.dept_name
ORDER BY d.dept_name, e.emp_no
`;
const [rows] = await connection.execute(sql, [
startDate,
endDate,
deptId || null,
deptId || null
]);
return {
success: true,
data: rows
};
} catch (error) {
throw error;
} finally {
connection.release();
}
}
}
酒店管理系统
核心功能:实时库存和并发控制
-- 房间表
CREATE TABLE rooms (
room_id INT PRIMARY KEY AUTO_INCREMENT,
room_no VARCHAR(10) UNIQUE NOT NULL,
room_type VARCHAR(20) NOT NULL, -- 标准间/大床房/套房
price DECIMAL(10,2) NOT NULL,
capacity INT,
floor INT,
status VARCHAR(20) DEFAULT '空闲', -- 空闲/入住/维修/预留
description TEXT
);
-- 预订表
CREATE TABLE reservations (
reservation_id INT PRIMARY KEY AUTO_INCREMENT,
reservation_no VARCHAR(20) UNIQUE,
guest_name VARCHAR(50) NOT NULL,
guest_phone VARCHAR(20),
room_type VARCHAR(20),
room_id INT,
check_in_date DATE NOT NULL,
check_out_date DATE NOT NULL,
num_guests INT,
status VARCHAR(20) DEFAULT '已确认', -- 已确认/已入住/已取消/已完成
total_amount DECIMAL(10,2),
deposit DECIMAL(10,2),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (room_id) REFERENCES rooms(room_id)
);
// 使用乐观锁处理并发预订
public class RoomReservationService {
public synchronized ReservationResult reserveRoom(ReservationDTO dto) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 1. 查询符合条件且有库存的房间
String findRoomSql = """
SELECT r.room_id, r.price, r.status
FROM rooms r
WHERE r.room_type = ?
AND r.status IN ('空闲', '预留')
AND r.room_id NOT IN (
SELECT room_id FROM reservations
WHERE status IN ('已确认', '已入住')
AND room_id IS NOT NULL
AND (
(check_in_date < ? AND check_out_date > ?) OR
(check_in_date < ? AND check_out_date > ?)
)
)
LIMIT 1
""";
ps = conn.prepareStatement(findRoomSql);
ps.setString(1, dto.getRoomType());
ps.setDate(2, dto.getCheckInDate());
ps.setDate(3, dto.getCheckOutDate());
ps.setDate(4, dto.getCheckOutDate());
ps.setDate(5, dto.getCheckInDate());
rs = ps.executeQuery();
if (!rs.next()) {
throw new RuntimeException("没有符合条件且空闲的房间");
}
int roomId = rs.getInt("room_id");
double price = rs.getDouble("price");
// 2. 生成预订号
String reservationNo = generateReservation