做JEE购物网站,数据库这步没弄好,后面Servlet、EJB、JPA、Spring全跟着遭殃。我平时用MySQL 8.0、JDK 11、Tomcat 9,存储引擎选InnoDB。建库先定字符集,别等中文商品名变问号才后悔。执行:
CREATE DATABASE shop_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER ''shop_app''@''%'' IDENTIFIED BY ''Shop@2024#App'';
GRANT SELECT,INSERT,UPDATE,DELETE ON shop_db.* TO ''shop_app''@''%'';
FLUSH PRIVILEGES;
生产环境别给应用账号DROP权限,只留增删改查。如果团队还在MySQL 5.7,把排序规则换成utf8mb4_general_ci,其他不变。
表从用户、商品、订单、购物车这几块下手。用户表t_user存登录信息,密码别存明文,用BCrypt哈希,长度给CHAR(60)。建表语句可以这样:
CREATE TABLE t_user (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash CHAR(60) NOT NULL,
email VARCHAR(100) DEFAULT NULL,
phone VARCHAR(20) DEFAULT NULL,
status TINYINT NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB;

商品分类用category,字段有id、name、parent_id、sort_order。商品表product要存分类、名称、副标题、价格、库存、主图、详情、状态。价格用DECIMAL(10,2),别用FLOAT,否则0.1+0.2能给你算出0.30000000000000004。库存用INT UNSIGNED,扣减时写UPDATE product SET stock=stock-? WHERE id=? AND stock>=?,看影响行数判断是否成功,这样能防超卖。商品表加索引idx_category(category_id)和idx_status_price(status,price),列表页查询会快很多。
订单表orders和订单明细order_item要一起设计。orders里放order_no、user_id、total_amount、pay_amount、status、address_snapshot、created_at、paid_at。order_no用CHAR(20)加唯一索引,地址快照存VARCHAR(500),因为用户改了收货地址不能影响历史订单。order_item里存order_id、product_id、product_name、product_price、quantity、subtotal,下单时把商品名和价格复制一份,商品调价后订单详情仍然准确。购物车cart_item用user_id和product_id做联合唯一键,避免同一商品重复加购。
外键要不要加?小团队做购物网站,建议加,能防脏数据。订单明细关联orders和product,购物车关联t_user和product。如果以后分库分表再考虑去掉。索引别乱加,orders表建idx_user_status(user_id,status)和idx_created(created_at),后台查用户订单和按时间统计都靠它。
JEE项目连接数据库,通常配JNDI数据源。Tomcat的context.xml里写:
username="shop_app" password="Shop@2024#App"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/shop_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowPublicKeyRetrieval=true"/>
web.xml里引用java:comp/env/jdbc/shopDB,JPA的persistence.xml或MyBatis配置同样用这个JNDI名。连接池最大20个连接,小网站够用,别一上来就设200,数据库先扛不住。
初始化脚本放src/main/resources/db/migration/V1__init.sql,用Flyway启动时自动执行,比手工导SQL靠谱。开发环境可以用Docker跑MySQL 8.0:
docker run --name shop-mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=shop_db -p 3306:3306 -v mysql-data:/var/lib/mysql -d mysql:8.0
建完表插几条测试数据,比如分类“数码”“服装”,商品“蓝牙耳机”价格299.00、库存100。用SELECT * FROM product WHERE status=1 AND category_id=1 ORDER BY id DESC LIMIT 10;验证索引和分页。下单逻辑放在同一个事务里:写orders、写order_item、扣库存、清购物车,任何一步失败都回滚。隔离级别用READ COMMITTED就够,防超卖靠条件更新,不靠悲观锁。
最后提醒几句:字符集统一utf8mb4,时区统一Asia/Shanghai,金额统一DECIMAL,图片存URL不存二进制,删除用status或deleted_at做逻辑删除。数据库建得稳,后面写JEE业务代码才不用天天改表。