# leyimall
**Repository Path**: liuhedev/leyimall
## Basic Information
- **Project Name**: leyimall
- **Description**: leyi mall
- **Primary Language**: Java
- **License**: AGPL-3.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-06-16
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# leyimall
#### 介绍
乐一商城
day8-FastDFS及ngnix配置
day11-elasticsearch
day14-GoodsApi 返回值为啥没有ResponseEntity?
#### 软件架构
商品相关内容,
- leyou-item-interface:主要是对外暴露的接口及相关实体类
- leyou-item-service:所有业务逻辑及内部使用接口
1、测试路由规则,在不用些control的情况,引入此依赖,即可在eureka web页面点击链接测试连通性
spring-boot-starter-actuator
2、zuul部署上之后,Zuul中默认就已经集成了Ribbon负载均衡和Hystrix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。错误信息:o.s.c.n.z.filters.post.SendErrorFilter : Error during filtering
3、com.github.pagehelper.PageHelper
PageHelper拦截的是org.apache.ibatis.executor.Executor的query方法,其传参的核心原理是通过ThreadLocal进行的,
当我们需要对某个查询进行分页查询时,我们可以再调用Mapper进行查询前调用一次PagerHelper.startPage(),这样PagerHelper会把分页信息存入ThreadLocal变量中。在拦截到Executor的query方法时则会从对应的ThreadLocal中获取分页信息,获取到了以后,则进行分页处理,处理完成后会把ThreadLocal中的分页信息处理掉,以便不影响下一次的查询操作。
4、Slf4j+logback/log4j2
slf4j:Simple Logging Facade for Java
```
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000
```
5、依赖注入的方式
依赖注入有三种方式:
```
(1)变量(filed)注入
优点:简洁、
(2)构造器注入
(3)set方法注入
```
6、图片上传说明
图片上传是文件的传输,如果也经过Zuul网关的代理,文件就会经过多次网路传输,造成不必要的网络负担。在高并发时,可能导致网络阻塞,Zuul网关不可用。这样我们的整个系统就瘫痪了。
7、商品规格设计
数据库设计:
```
//商品规格信息,同一spu,规格类型基本一致
// 规格参数分组表
create table `t_spec_group` (
`id` bigint(20) not null auto_increment comment '主键',
`cid` bigint(20) not null comment ’商品分类id,一个分类下有多个规格组‘,
`name` varchar(50) not null commect '规格组名称',
primary key(`id`),
key `key_category`(`cid`)
) charset=utf8 comment='规格参数的分组表,每个商品分类下有多个规格参数组';
// 规格参数表
CREATE TABLE `tb_spec_param` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`cid` bigint(20) NOT NULL COMMENT '商品分类id',
`group_id` bigint(20) NOT NULL,
`name` varchar(255) NOT NULL COMMENT '参数名',
`numeric` tinyint(1) NOT NULL COMMENT '是否是数字类型参数,true或false',
`unit` varchar(255) DEFAULT '' COMMENT '数字类型参数的单位,非数字类型可以为空',
`generic` tinyint(1) NOT NULL COMMENT '是否是sku通用属性,true或false',
`searching` tinyint(1) NOT NULL COMMENT '是否用于搜索过滤,true或false',
`segments` varchar(1000) DEFAULT '' COMMENT '数值类型参数,如果需要搜索,则添加分段间隔值,如CPU频率间隔:0.5-1.0',
PRIMARY KEY (`id`),
KEY `key_group` (`group_id`),
KEY `key_category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='规格参数组下的参数名';
// spu表
create table `t_spu`(
`id` bigint(20) not null auto_increment comment 'spu id',
`title` varchar(128) not null default '' comment '标题',
`sub_title` varchar(256) not null default '' comment '副标题',
`cid1` bigint(20) not null comment '1级类目id',
'cid2' bigint(20) not null comment '2级类目id',
`cid3` bigint(20) not null comment '3级类目id',
`saleable` tinyint(1) not null default '1' comment '是否上架:0下架,1上架',
`valid` tinyint(1) not null default '1' comment '是否有效,0已删除,1有效',
`create_time` datetime default null comment '添加时间',
`last_update_time` datetime default null comment '最后更新时间',
primary key(`id`)
) charset=utf8 comment='spu表';
// spu detail表
因为spu表数据量比较大,所以对spu表做了垂直拆分,将spu的详情信息放到t_spu_detail表中
CREATE TABLE `tb_spu_detail` (
`spu_id` bigint(20) NOT NULL,
`description` text COMMENT '商品描述信息',
`generic_spec` varchar(10000) NOT NULL DEFAULT '' COMMENT '通用规格参数数据',
`special_spec` varchar(1000) NOT NULL COMMENT '特有规格参数及可选值信息,json格式',
`packing_list` varchar(3000) DEFAULT '' COMMENT '包装清单',
`after_service` varchar(3000) DEFAULT '' COMMENT '售后服务',
PRIMARY KEY (`spu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment 'spu详情页及规格选择数据';
// sku表
indexs设计,方便通过角标快速定位到sku。
CREATE TABLE `tb_sku` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'sku id',
`spu_id` bigint(20) NOT NULL COMMENT 'spu id',
`title` varchar(255) NOT NULL COMMENT '商品标题',
`images` varchar(1000) DEFAULT '' COMMENT '商品的图片,多个图片以‘,’分割',
`price` bigint(15) NOT NULL DEFAULT '0' COMMENT '销售价格,单位为分',
`indexes` varchar(100) COMMENT '特有规格属性在spu属性模板中的对应下标组合',
`own_spec` varchar(1000) COMMENT 'sku的特有规格参数,json格式',
`enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效,0无效,1有效',
`create_time` datetime NOT NULL COMMENT '添加时间',
`last_update_time` datetime NOT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`),
KEY `key_spu_id` (`spu_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='sku表,该表表示具体的商品实体,如黑色的64GB的iphone 8';
// 库存
因为库存字段写频率较高,而sku的其他字段以读为主,因此我们将两个表分离,读写不会干扰。
CREATE TABLE `tb_stock` (
`sku_id` bigint(20) NOT NULL COMMENT '库存对应的商品sku id',
`seckill_stock` int(9) DEFAULT '0' COMMENT '可秒杀库存',
`seckill_total` int(9) DEFAULT '0' COMMENT '秒杀总数量',
`stock` int(9) NOT NULL COMMENT '库存数量',
PRIMARY KEY (`sku_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存表,代表库存,秒杀库存等信息';
```
7、java中常用概念
do: data object
po:persistant object持久对象, bean,entity等命名;
bo:business object业务对象, service、manage、business等命名;
vo:value object值对象,主要体现在视图的对象;
dto: Data transfer object数据传输对象,经过处理后的po,可能增加或者减少po的属性;
pojo:plan ordinary java object简单java对象,即pojo是一个简单的java对象,他不包含业务逻辑或持久逻辑等,但不是JavaBean、EntityBean等,不具有任何特殊角色和不继承或者不实现任何其它Java框架的类或接口。
8、tk mybatis实体字段存在关键字、保留字,执行报错
```
The error occurred while setting parameters ### SQL: SELECT id,cid,group_id,name,numeric,unit,generic,searching,segments FROM tb_spec_param WHERE cid = ? ###
```
其中,numeric为保留字,解决方案为持久化对象中使用@Column("`numeric`")标注一下。
9、@Transactional的使用
Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。
使用@Transactional的相比传统的我们需要手动开启事务,然后提交事务来说。它提供如下方便
- 根据你的配置,设置是否自动开启事务
- 自动提交事务或者遇到异常自动回滚
```
@Service
public class StudentService {
@Autowired
StudentDao studentDao;
@Transactional
public void innerSave(int i) {
Student student = new Student();
student.setName("test" + i);
studentDao.save(student);
//i=5 会出现异常
int a = 1 / (i - 5);
}
}
```
10、@Transient
@Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性;
如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则ORM框架默认其注解为@Basic;
```
public class SkuDo {
private Long id; // skuId
@Transient
private Integer stock;// 库存
}
```
@JsonIgnore
作用:在json序列化时将pojo中的一些属性忽略掉,标记在属性或者方法上,返回的json数据即不包含该属性。
```
com.fasterxml.jackson.core
jackson-annotations
compile
```
11、理解JPA注解
- @Entity : 表示该类是一个实体,也就是和表形成映射,可以添加属性来指定对应的表
如:@Entity(name="t_user")
- @Table : 指定表名,非必须填写,可以在entity注解上直接表示表名。但是@Table 就是改变某些默认的映射规则,如表名,schema等,可以添加索引和约束,看一下它的定义
如 : @Table(name="t_user")
- @Id : 用于表示主键,指定哪一个属性和主键对应 可以在变量上声明,也可以在get方法上声明,建议统一。
- @GeneratedValue : 用于表示主键生成策略 主键生成策略,提供的有4种
@Entity可以和@Table一起使用,但是@Table设置的优先级较高。
```
1、AUTO 自动选择一个最适合底层数据库的主键生成策略。如MySQL会自动对应auto increment。这个是默认选项,即如果只写@GeneratedValue,等价于@GeneratedValue(strategy=GenerationType.AUTO)。注意在mysql5 + hibernate 5的版本测试下,会产生另外一张表,用于记录主键值。 可以在核心配资文件中添加此属性来达到native效果
false
2、IDENTITY 表自增长字段,Oracle不支持这种方式。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
3、SEQUENCE 通过序列产生主键,MySQL不支持这种方式。
4、TABLE 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如 OpenJPA生成openjpa_sequence_table表,Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。
```
以上,测试发现@Entity在配合tx.mybatis使用的时候,设置的表名不生效,依然默认使用类名小写。
12、Java8 .stream() .map() .collect()用法
```
mylist.stream()
.map(fun->{
return item;
}).collection(Collection.toList());
```
stream(流)是一个来自数据源的元素队列并支持聚合操作。
* 聚合操作:类似于sql语句一样的操作,比如filter\map\reduce\find\match\sorted等。
stream的基本步骤:(
(1)创建stream
(2)中间操作:转换stream,每次转换原stream对象不改变,返回一个新的stream对象(可以有多次转换)
(3)结束操作:对stream进行聚合(reduce)操作,获取想要的结果。

参考:https://zhuanlan.zhihu.com/p/94882031
13、spring-boot-starter-data-jpa和mybatis
Spring Data JPA与MyBatis对比,起始也就是hibernate与MyBatis对比。所以,我们直接来比较后两者。
* JPA是一个规范,而不是框架
* Hibernate是JPA的一种实现,是一个框架
* Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,底层使用hibernate。
* MyBatis不是JPA体系,需要写sql语句,它是半自动ORM框架
14、hibernate.validator