提交 95b8debc 编写于 作者: Q qiurunze123

数据库

上级 52b6f609
......@@ -86,8 +86,8 @@
#### [分布式治理框架-dubbo - zk - 解析--未更新](/docs/redis-code.md)
#### [通信mq-Kafka--未更新](/docs/redis-code.md)
#### [微服务框架--未更新](/docs/redis-code.md)
#### [lua学习](/docs/redis-lua.md)
#### [netty专题](/docs/netty.md)
#### [mysql数据库优化及架构学习](/docs/mysql.md)
#### [netty专题(已更新 by liuxiangyu)](/docs/netty.md)
#### [linux专题](/docs/linux.md)
#### [面试专题(最后更新)--未更新](/docs/code-solve.md)
......
### mysql数据库设计与优化与架构 模拟场景(京东商城)
任何优化多需要场景,本次所有的场景为京东商城的数据库设计模拟!
有问题或者宝贵意见联系我的QQ,非常希望你的加入!
##简介:
设计:
1.数据库开发规范的制定
2.数据库结构与设计
3.mysql执行计划的分析
4.mysql数据库的备份和恢复
5.mysql高性能高可用架构变迁
**场景说明**
用户登录->选购商品->加购物车->检查库存->提交订单->货到付款-- Y -- 发货
|N--订单付款
用户模块 -- 完成用户注册和登录验证
商品模块 -- 前后台商品管理和游览
订单模块 -- 订单和购物车的生成和管理
仓配模块 -- 仓库库存和物流的管理
**数据库设计规范**
逻辑设计 + 物理设计
1.数据库命名规范
2.数据库基本设计规范
3.数据库索引设计规范
4.数据库字段设计规范
5.数据库的sql开发规范
数据库操作行为规范(运维标准)
数据库设计规范
1.所有的数据库对象名称必须使用小写字母并用下划线分割(mysql数据库大小写敏感)
例如: 不同的数据库名 DbName dbname 不同的表名 Table table taBLe
2.所有数据库对象名称禁止使用mysql保留关键字
例如 :select id , username , from ,age from table_user 会造成mysql 歧义
3.数据库对象的命名要做到见名识义,并且最好不要超过32个字符
例如:秒杀用户表 miaosha_userdb good!!
用户账号表 user_account good!!
4.所有的临时表必须义tmp为前缀并且已日期为后缀,备份库备份表必须义bak为前缀并且已日期为后缀,大的可以到处sql
5.所有的数据存储的列名和列类型必须一致
custom_inf order_master
customer_id int unsigned customer_id int unsigned
必须一致否则会影响性能,一般这种列都是作为表的关联列,如果两个字段的数据类型不同,数据库则会进行隐式的数据类型
转换降低性能,造成列上的索引失效!!
存储规范
1.所有的表必须使用Innodb存储引擎 支持事物行级锁,更好的恢复性,并发性能更好
2.大部分数据库表字符集要统一 (大部分使用UTF-8) 编码乱码
3.所有的表和字段都要添加注释 数据字典的维护
4.尽量控制单表的数据量大小,建议控制在500万以内 当然500万并不是mysql的限制
过大可以通过历史数据归档,分库分表的手段来控制数据量的大小(订单表一类的比较重要)
5.尽量做到冷热数据分离,减少表的宽度 列最大4096列
减少磁盘io,保证热数据的内存缓存命中率,控制列数量也可以更加有效的利用缓存,避免读入无用的冷数据
经常使用的列放在一个表中
6.禁止在表中建立预留字段
预留字段命名很难做到见识义,无法选择合适的类型,对预留字段修改会对表进行锁定
行为规范
1.禁止存储图片,文件等二进制文件,造成大量的io操作 (存在相应的文件服务器上)
2.禁止再线上进行数据库的压力测试
3.禁止从开发环境测试环境直连生产环境
索引设计规范(不要滥用索引)
1.建议单表索引数量不超过5个 索引并不是越多越好过多索引降低效率,优化器过多索引选出最优解
innodb 是按照那个索引的顺序来组织表的呢 主键
不使用更新频繁的列作为主键,不使用多列主键
不使用uuid,md5,hash 字符串列作为主键 不能保证顺序增长
2.那些哪些列上建立索引???
1.我们经常在select update delete语句的where从句的列建立索引
2.包含在order by , group by , distinct 中的字段
3.多表join的关联列
3.如何选择索引的顺序?
联合索引中 索引从左到右的顺序
建立索引的目的 查询数据的时候可以根据索引来进行数据查找-- 从而减少磁盘的随机io , 增加查询的性能,所以
如果我们的索引能够过滤出更少的数据那么我们从磁盘读入的数据则越少
1.区分度最高的列放在联合索引的最左侧 区分度--数据唯一值的数量/总行数 区分度最大的就应该是主键了
2.尽量字段长度小的列放在联合索引的最左侧
3.使用最频繁的列放在最左侧
4,尽量避免冗余和重复的索引 重复索引了: primary key(id) , index(id) , unique index(id)
冗余: index(a,b,c) , index(a.b)
5.对于频繁使用的查询先优先考虑覆盖索引(包含了所有的查询字段的索引)
6.尽量使用外键 不建议使用外检约束,但是一定要在表与表之间的关联键上建立索引
\ No newline at end of file
package com.geekq.miaosha.common.enums;
public class MessageStatus {
public static final Integer ZORE = 0;
/**
* 消息类型
*/
public enum messageType {
maiosha_message("秒杀消息"),
buy_message("购买消息"),
system_message("系统消息");
private String message;
private messageType(String message){
this.message = message;
}
public String getMessage() {
return message;
}
}
/**
* 消息内容
*/
public enum ContentEnum {
system_message_register(7000,"尊敬的用户你好,你已经成功注册!"),
system_message_register_head(7001,"注册成功");
private int code;
private String message;
private ContentEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
/**
* 消息类型
*/
public enum sendType {
// maiosha_message("秒杀消息"),
// buy_message("购买消息"),
// system_message("系统消息");
// private String message;
//
// private messageType(String message){
// this.message = message;
// }
//
// public String getMessage() {
// return message;
// }
}
}
......@@ -44,7 +44,7 @@ public enum ResultStatus {
MOBILE_ERROR (30008,"手机号格式错误!"),
MOBILE_NOT_EXIST (30009,"手机号不存在!"),
PASSWORD_ERROR (30010,"密码错误!"),
USER_NOT_EXIST(30011,"用户不存在!"),
/**
* 订单模块
......
package com.geekq.miaosha.controller;
import com.geekq.miaosha.common.SnowflakeIdWorker;
import com.geekq.miaosha.domain.MiaoShaMessageUser;
import com.geekq.miaosha.common.enums.MessageStatus;
import com.geekq.miaosha.common.enums.ResultStatus;
import com.geekq.miaosha.common.resultbean.ResultGeekQ;
import com.geekq.miaosha.domain.MiaoShaMessageInfo;
import com.geekq.miaosha.rabbitmq.MQSender;
import com.geekq.miaosha.service.MiaoShaMessageService;
import com.geekq.miaosha.vo.MiaoShaMessageVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.List;
@Controller
......@@ -17,20 +21,36 @@ import java.util.List;
public class MiaoShaMessageController {
@Autowired
private MiaoShaMessageService messageService ;
private MiaoShaMessageService messageService;
@Autowired
private MQSender sendMessage;
@RequestMapping(value="/list", produces="text/html")
public void list() {
MiaoShaMessageVo vo = new MiaoShaMessageVo();
vo.setContent("尊敬的用户你好,你已经成功注册!");
vo.setCreateTime(new Date());
vo.setMessageId(SnowflakeIdWorker.getOrderId(0,0));
vo.setSendType(0);
vo.setStatus(0);
vo.setUserId(Long.valueOf(22));
sendMessage.sendRegisterMessage(vo);
@RequestMapping(value = "/list", produces = "text/html")
public String list(@RequestParam(value = "userid",required= true) String userId, Model model) {
ResultGeekQ resultGeekQ = ResultGeekQ.build();
if (StringUtils.isBlank(userId)) {
resultGeekQ.withError(ResultStatus.USER_NOT_EXIST);
}
List<MiaoShaMessageInfo> miaoShaMessageInfos = messageService.getmessageUserList(Long.valueOf(userId), null);
model.addAttribute("message",miaoShaMessageInfos);
return "message_list";
}
@RequestMapping(value = "/getNewMessage", produces = "text/html")
@ResponseBody
public String getNewMessage(@RequestParam(value = "userid",required= true) String userId, Model model) {
if (StringUtils.isBlank(userId)) {
return "0";
}
List<MiaoShaMessageInfo> miaoShaMessageInfos = messageService.getmessageUserList(Long.valueOf(userId),MessageStatus.ZORE);
if(miaoShaMessageInfos.isEmpty()){
return "0";
}else {
return "1";
}
};
}
......@@ -13,8 +13,8 @@ public interface MiaoShaMessageDao {
public List<MiaoShaMessageInfo> listMiaoShaMessage(@Param("messageId") String messageId);
@Select("<script>select * from miaosha_message_user where 1=1 <if test=\"messageId !=null \">and messageId = #{messageId} </if></script>")
public List<MiaoShaMessageUser> listMiaoShaMessageUser(@Param("messageId") String messageId);
@Insert("insert into miaosha_message (id , messageid ,content , create_time ,status,over_time,message_type ,send_type , good_name , price)" +
"value (#{id},#{messageId},#{content},#{createTime},#{status},#{overTime},#{messageType},#{sendType},#{goodName},#{price}) ")
@Insert("insert into miaosha_message (id , messageid ,content , create_time ,status,over_time,message_type ,send_type , good_name , price,messageHead)" +
"value (#{id},#{messageId},#{content},#{createTime},#{status},#{overTime},#{messageType},#{sendType},#{goodName},#{price},#{messageHead}) ")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
public void insertMiaoShaMessage(MiaoShaMessageInfo miaoShaMessage);
......@@ -22,4 +22,9 @@ public interface MiaoShaMessageDao {
"value (#{id},#{userId},#{messageId},#{goodId},#{orderId}) ")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
public void insertMiaoShaMessageUser(MiaoShaMessageUser miaoShaMessageUser);
@Select(" <script> select * from miaosha_message_user mmu , miaosha_message mm where " +
" mmu.messageid = mm.messageid and userid=${userId} <if test=\"status !=null \">and status = #{status} </if></script> ")
public List<MiaoShaMessageInfo> listMiaoShaMessageByUserId(@Param("userId") long userId,@Param("status") Integer status );
}
package com.geekq.miaosha.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
......@@ -7,12 +12,18 @@ import java.util.Date;
/**
* 消息中心主体表
*/
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MiaoShaMessageInfo implements Serializable {
private Integer id ;
private Long messageId ;
private Long userId ;
private String content ;
private Date createTime;
......@@ -29,84 +40,6 @@ public class MiaoShaMessageInfo implements Serializable {
private BigDecimal price ;
private String messageHead ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Long getMessageId() {
return messageId;
}
public void setMessageId(Long messageId) {
this.messageId = messageId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getOverTime() {
return overTime;
}
public void setOverTime(Date overTime) {
this.overTime = overTime;
}
public Integer getMessageType() {
return messageType;
}
public void setMessageType(Integer messageType) {
this.messageType = messageType;
}
public Integer getSendType() {
return sendType;
}
public void setSendType(Integer sendType) {
this.sendType = sendType;
}
public String getGoodName() {
return goodName;
}
public void setGoodName(String goodName) {
this.goodName = goodName;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
package com.geekq.miaosha.service;
import com.geekq.miaosha.common.enums.MessageStatus;
import com.geekq.miaosha.dao.MiaoShaMessageDao;
import com.geekq.miaosha.domain.MiaoShaMessageInfo;
import com.geekq.miaosha.domain.MiaoShaMessageUser;
......@@ -19,11 +20,8 @@ public class MiaoShaMessageService {
@Autowired
private MiaoShaMessageDao messageDao;
public List<MiaoShaMessageUser> getMessage( String userId ){
List<MiaoShaMessageUser> messageUserList = messageDao.listMiaoShaMessageUser(userId);
return messageUserList;
public List<MiaoShaMessageInfo> getmessageUserList( Long userId , Integer status ){
return messageDao.listMiaoShaMessageByUserId(userId,status);
}
......@@ -41,6 +39,7 @@ public class MiaoShaMessageService {
miaoshaMessage.setSendType(miaoShaMessageVo.getSendType());
miaoshaMessage.setMessageId(miaoShaMessageVo.getMessageId());
miaoshaMessage.setCreateTime(new Date());
miaoshaMessage.setMessageHead(miaoShaMessageVo.getMessageHead());
messageDao.insertMiaoShaMessage(miaoshaMessage);
}
}
package com.geekq.miaosha.service;
import com.geekq.miaosha.common.SnowflakeIdWorker;
import com.geekq.miaosha.common.enums.MessageStatus;
import com.geekq.miaosha.controller.RegisterController;
import com.geekq.miaosha.dao.MiaoShaUserDao;
import com.geekq.miaosha.domain.MiaoshaUser;
......@@ -110,7 +111,9 @@ public class MiaoShaUserService {
vo.setMessageId(SnowflakeIdWorker.getOrderId(0,0));
vo.setSendType(0);
vo.setStatus(0);
vo.setMessageType(MessageStatus.messageType.system_message.ordinal());
vo.setUserId(miaoShaUser.getId());
vo.setMessageHead(MessageStatus.ContentEnum.system_message_register_head.getMessage());
sender.sendRegisterMessage(vo);
......
......@@ -40,4 +40,7 @@ public class MiaoShaMessageVo implements Serializable {
private String goodName ;
private BigDecimal price ;
private String messageHead ;
}
......@@ -20,7 +20,7 @@ mybatis.config-locations=classpath:mybatis/config.xml
#datasource
spring.datasource.url=jdbc:mysql://localhost:3306/miaosha?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=nihaoma
spring.datasource.password=aixiyue11
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#druid
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
......
......@@ -18,11 +18,15 @@
<!-- common.js -->
<script type="text/javascript" th:src="@{/js/common.js}"></script>
</head>
<body>
<div class="panel panel-default">
<div class="panel-heading">秒杀商品列表11</div>
<div class="panel-heading"><a href="">消息中心</a></div>  
<div class="panel-heading">
<button onclick="messageRegister()">消息中心</button>
<input id="userid" th:value="${user.id}"></input>
</div>  
<table class="table" id="goodslist">
<tr><td>商品名称</td><td>商品图片</td><td>商品原价</td><td>秒杀价</td><td>库存数量</td><td>详情</td></tr>
<tr th:each="goods,goodsStat : ${goodsList}">
......@@ -36,4 +40,12 @@
</table>
</div>
</body>
<script>
function messageRegister() {
var userid = $("#userid").val();
window.location.href='/message/list?userid='+userid;
}
</script>
</html>
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>消息中心列表</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- jquery -->
<script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
<!-- bootstrap -->
<link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
<script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
<!-- jquery-validator -->
<script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
<script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
<!-- layer -->
<script type="text/javascript" th:src="@{/layer/layer.js}"></script>
<!-- md5.js -->
<script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
<!-- common.js -->
<script type="text/javascript" th:src="@{/js/common.js}"></script>
</head>
<body>
<div class="panel panel-default">
<div class="panel-heading">消息列表</div>
<input class="panel-heading" style="display:none" name="t1" id="t1" value="有新消息"></input>
<table class="table" id="message">
<tr><td>消息名称</td><td>消息类型</td><td>消息内容</td><td>创建时间</td></tr>
<tr th:each="messages,goodsStat : ${message}">
<td th:text="${messages.messageHead}"></td>
<td th:if="${messages.messageType eq 0}">秒杀消息</td>
<td th:if="${messages.messageType eq 1}">购买消息</td>
<td th:if="${messages.messageType eq 2}">系统消息</td>
<input id="userid" th:value="${messages.userId}" th:type="hidden"></input>
<td th:text="${messages.content}"></td>
<td th:text="${#dates.format(messages.createTime, 'yyyy-MM-dd')}" colspan="2"></td>
</tr>
</table>
</div>
</body>
<script>
setInterval(function(){
messageKeeping();
},5000);
// window.onload = function(){
// //页面加载即执行函数
// messageKeeping();
// }
function messageKeeping() {
$.ajax({
url: "/message/getNewMessage",
type: "GET",
async:true,
data: {
userid: $("#userid").val(),
},
success: function (data) {
if(data == 1){
$("#t1").css({'display':'block'});
}else{
$("#t1").css({'display':'none'});
}
},
error: function () {
layer.msg("客户端请求有误");
}
});
// setTimeout('messageKeeping()', 100000); //注意:执行的函数需要加引号,否则会报错的
}
</script>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册