## 一、简单查询
自定义的简单查询就是根据方法名来自动生成 SQL,主要的语法是`findXXBy`,`readAXXBy`,`queryXXBy`,`countXXBy`,`getXXBy`后面跟属性名称:
~~~
User findByUserName(String userName);
~~~
也使用一些加一些关键字`And`、`Or`
~~~
User findByUserNameOrEmail(String username, String email);
~~~
修改、删除、统计也是类似语法
~~~
Long deleteById(Long id);
Long countByUserName(String userName)
~~~
基本上 SQL 体系中的关键词都可以使用,例如:`LIKE`、`IgnoreCase`、`OrderBy`。
~~~
List<User> findByEmailLike(String email);//传入的like字符串,根据需要,可以为%test%形式,或%test,或test%等
List<SysProxyLog> findByRequestAddrLikeAndRequestBodyLike(String requestAddr, String requestBody);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);
#多个order by
List<CardPooledQuota> findByCardIdAndReviseValidTimeLessThanEqualOrderByReviseInvalidTimeAscPackageTypeAsc(long cardId, String reviseValidTime);
~~~
**具体的关键字,使用方法和生产成SQL如下表所示**
| Keyword | Sample | JPQL snippet |
| --- | --- | --- |
| And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
| Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
| Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
| Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
| LessThan | findByAgeLessThan | … where x.age < ?1 |
| LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
| GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
| GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
| After | findByStartDateAfter | … where x.startDate > ?1 |
| Before | findByStartDateBefore | … where x.startDate < ?1 |
| IsNull | findByAgeIsNull | … where x.age is null |
| IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
| Like | findByFirstnameLike | … where x.firstname like ?1 |
| NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
| StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
| EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
| Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
| OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
| Not | findByLastnameNot | … where x.lastname <> ?1 |
| In | findByAgeIn(Collectionages) | … where x.age in ?1 |
| NotIn | findByAgeNotIn(Collectionage) | … where x.age not in ?1 |
| TRUE | findByActiveTrue() | … where x.active = true |
| FALSE | findByActiveFalse() | … where x.active = false |
| IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
## 二、自定义多表语句(JPQL)
其实 Spring Data 觉大部分的 SQL 都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的 SQL 来查询,Spring Data 也是完美支持的;在 SQL 的查询方法上面使用@Query注解;
>[danger] 如涉及到删除和修改在需要加上@Modifying也可以根据需要添加@Transactional对事务的支持,查询超时的设置等;
```
@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String userName, Long id);
```
```
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
```
```
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
@Query("select staff from SysStaff staff where exists (select 1 from SysStaffInvitation siv where siv.staffId=staff.staffId and siv.fromStaffId=?1 and staff.createTime like ?2%)")
List<SysStaff> getInvitedSysStaffList(long staffId, String invitationTime);
```
**命名查询和占位符查询**
命名查询中,参数必须加上@Param定义;
占位符查询,则需要注意,索引序号从1开始;
```
@Query("select role from SysRole role,SysStaffRole sr where sr.roleId = role.roleId and sr.staffId = ?1")
List<SysRole> getRoleListBySaffId(long staffId);
```
```
@Query("select staff from SysStaff staff,SysStaffRole sr where sr.staffId = staff.staffId and sr.roleId = :roleId")
List<SysStaff> getSysStaffListOfSpecRole(@Param("roleId") long roleId);
```
**IN子句及判空条件**
传入的参数不能是字符串,必须是集合;
例如:List<Long> filterDepartmentIds
判空:coalesce(?6, null)
```
@Query(value = "select staff from SysStaff staff where staff.sts=" + StaffStatus.VALID //
+ " and (?1=0L or staff.domainId=?1)"//
+ " and (?2=0L or staff.departmentId=?2)"// filterDepartmentId
+ " and (?3=0L or staff.corporationId=?3)"// filterCorporationId
+ " and (?4=0L or exists(select 1 from SysStaffRole sr where sr.staffId=staff.staffId and sr.roleId=?4))"// filterRoleId
+ " and (?5=0L or exists(select 1 from SysStaffSetting ss where ss.staffId=staff.staffId and ss.identityId=?5))"// filterIdentityId
+ " and (coalesce(?6, null) is null or staff.departmentId in (?6))"// filterDepartmentIds
+ " and (coalesce(?7, null) is null or staff.corporationId in (?7))"// filterCorporationIds
+ " and (coalesce(?8, null) is null or exists(select 1 from SysStaffRole sr where sr.staffId=staff.staffId and sr.roleId in (?8)))"// filterRoleIds
+ " and (coalesce(?9, null) is null or exists(select 1 from SysStaffSetting ss where ss.staffId=staff.staffId and ss.identityId in (?9)))"// filterIdentityIds
+ " and (?10 is null or ?10 = '' or staff.staffCode like ?10)"// staffCode
+ " and (?11 is null or ?11 = '' or staff.staffName like ?11)"// staffName
+ " and (?12 is null or ?12 = '' or staff.roleNames like ?12)"// roleNames
+ " and (?13=0L or staff.departmentId=?13)"// departmentId
)
Page<SysStaff> getStaffOfSpecCondintionForComponent(long filterDomainId, long filterDepartmentId, long filterCorporationId, long filterRoleId, long filterIdentityId, List<Long> filterDepartmentIds, List<Long> filterCorporationIds, List<Long> filterRoleIds, List<Long> filterIdentityIds, String staffCode, String staffName, String roleNames, long departmentId, Pageable pageable);
```
注意使用的时候,需要确保List默认值为null;
```
sysStaffDao.getStaffOfSpecCondintionForComponent(filterDomainId, filterDepartmentId, filterCorporationId, filterRoleId, filterIdentityId, filterDepartmentIds.size() == 0 ? null : filterDepartmentIds, filterCorporationIds.size() == 0 ? null : filterCorporationIds, filterRoleIds.size() == 0 ? null : filterRoleIds, filterIdentityIds.size() == 0 ? null : filterIdentityIds, staffCode, staffName, roleNames, departmentId, PagableBuilder.getPageable(curPage, pageSize, orderFieldName, orderDirection))
```
**模糊查询**
```
@Query("select department from SysDepartment department where department.parentDepartmentId=?1 and department.sts=" + DepartmentStatus.VALID //
+ " and (?2 is null or ?2 = '' or department.departmentName like ?2)" //
+ " and (?3 is null or ?3 = '' or department.departmentFullName like ?3)" //
+ " and (?4 is null or ?4 = '' or department.departmentCode like ?4)" //
)
List<SysDepartment> getChildDepartmentsOfSpecDepartment(long departmentId, String subDepartmentName, String subDepartmentFullName, String subDepartmentCode);
```
调用:
```
sysDepartmentDao.getChildDepartmentsOfSpecDepartment(departmentId, wrapLike(subDepartmentName, false), wrapLike(subDepartmentFullName, false), wrapLike(subDepartmentCode, false))
```
## 三、动态查询条件
使用JpaSpecificationExecutor;
构建Specification查询条件,然后传给JpaSpecificationExecutor的findAll(包含List<T>或Page<T>两种返回值,代表分页与非分页的方法),分页的在Specification之后多传入一个Pageable pageable参数;
一般将这种判断逻辑代码封装在Service中,最后调用JpaSpecificationExecutor的方法,参考如下:
![](https://img.kancloud.cn/9c/70/9c706c462eed7c619c095810124ed735_1127x457.png)
## 四、Predicate
### **OR**
```
Predicate predicate1 = criteriaBuilder.like(root.get("goodsTitle"), keyword);
Predicate predicate2 = criteriaBuilder.like(root.get("eShopName"), keyword);
predicates.add(criteriaBuilder.or(predicate1, predicate2));
```
### **IN**
```
List<Long> myAgentList = sysStaffRelationDao.getStaffIdListByRelatedStaffIdAndRelationType(model.getCurLoginData().getCurStaffId(), RayiotSysStaffRelationType.parent_agent);
myAgentList.add(model.getCurLoginData().getCurStaffId());
In<Long> inStaffIdListClause= criteriaBuilder.in(root.get("terminalAgentStaff"));
for (Long id : myAgentList)
{
inStaffIdListClause.value(id);
}
predicates.add(inStaffIdListClause);
```
### **EXIST**
```
List<Predicate> predicates = new ArrayList<>();
if (!StringUtil.isEmpty(staffName))
{
predicates.add(criteriaBuilder.like(root.get("staffName"), wrapLike(staffName)));
}
if (!StringUtil.isEmpty(staffCode))
{
predicates.add(criteriaBuilder.like(root.get("staffCode"), wrapLike(staffCode)));
}
Subquery<SysStaffRole> subquery = query.subquery(SysStaffRole.class);
Root<SysStaffRole> subRoot = subquery.from(SysStaffRole.class);
subquery.select(subRoot.get("id"));
subquery.where(criteriaBuilder.equal(subRoot.get("roleId"), roleId), criteriaBuilder.equal(subRoot.get("staffId"), root.get("staffId")));
predicates.add(criteriaBuilder.exists(subquery));
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
```
### **关联表**
**不推荐使用,因为需要在实体中,建立好映射;**
```
List<Predicate> predicates = new ArrayList<>();
if (!StringUtil.isEmpty(staffName))
{
Join<SysStaffDialogue, SysStaff> startStaffJoin = root.join("SysStaff", JoinType.INNER);
startStaffJoin.on(criteriaBuilder.equal(startStaffJoin.get("staffId"), root.get("staffId")));
predicates.add(criteriaBuilder.like(startStaffJoin.get("staffName"), wrapLike(staffName)));
}
if (!StringUtil.isEmpty(dialogicalStaffName))
{
Join<SysStaffDialogue, SysStaff> dialogicalStaffJoin = root.join("SysStaff", JoinType.INNER);
dialogicalStaffJoin.on(criteriaBuilder.equal(dialogicalStaffJoin.get("staffId"), root.get("dialogicalStaffId")));
predicates.add(criteriaBuilder.like(dialogicalStaffJoin.get("staffName"), wrapLike(dialogicalStaffName)));
}
if (!StringUtil.isEmpty(getFirstDateTimePossible(startTimeDateTimeScope)))
{
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("startTime"), getFirstDateTimePossible(startTimeDateTimeScope)));
}
if (!StringUtil.isEmpty(getSecondDateTimePossible(startTimeDateTimeScope)))
{
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("startTime"), getSecondDateTimePossible(startTimeDateTimeScope)));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
```
## 五、@Query
```
@Query("from CardSource where isValid=" + YesOrNo.YES)
```
>[danger] 这里写入@Query里面的常量定义,必须用final来修饰;
## 六、构造新对象
构造一个新的对象:
定义一个对象:
```
public class CardFlowPackageOrderObject implements Serializable
{
private long packageId;
private String packageName;
private Long salePrice;
public CardFlowPackageOrderObject(long packageId, String packageName, Long salePrice)
{
this.packageId = packageId;
this.packageName = packageName;
this.salePrice = salePrice;
}
public long getPackageId()
{
return packageId;
}
public void setPackageId(long packageId)
{
this.packageId = packageId;
}
public String getPackageName()
{
return packageName;
}
public void setPackageName(String packageName)
{
this.packageName = packageName;
}
public Long getSalePrice()
{
return salePrice;
}
public void setSalePrice(Long salePrice)
{
this.salePrice = salePrice;
}
}
```
构成新对象的dao方法:
```
@Query(value = "select new com.ray.iot.controller.data.meta.CardFlowPackageOrderObject(cfp.packageId, cfp.packageName, cfp.salePrice) from CardFlowPackage cfp where cfp.cardSource=?1 and cfp.packageStatus=?2 and cfp.packageType=?3"//
)
List<CardFlowPackageOrderObject> getCardFlowPackageOfInnerAndCardSourceAndPackageStatusAndPackageType(long cardSource, long packageStatus, long packageType);
@Query(value = "select new com.ray.iot.controller.data.meta.CardFlowPackageOrderObject(cfp.packageId, cfp.packageName, cafp.agentSalePrice) from CardFlowPackage cfp,CardAgentFlowPackage cafp where cfp.cardSource=?1 and cfp.packageStatus=?2 and cfp.packageType=?3"//
+ " and cafp.packageId=cfp.packageId and cafp.agentStaffId=?4 and cafp.agentPackageStatus=" + CardAgentPackageStatus.enabled //
)
List<CardFlowPackageOrderObject> getCardFlowPackageOfWechatAccessAndCardSourceAndPackageStatusAndPackageType(long cardSource, long packageStatus, long packageType, long wechatTopAgentStaffId);
@Query("select new org.ray.framework.system.controller.data.account.sysrelationmodel.SysStaffWithRelationFlag(staff,1) from SysStaff staff where not exists(select 1 from SysStaffRelation sr where sr.staffId=staff.staffId and sr.relationType=?1)")
List<SysStaffWithRelationFlag> getStaffListNotRelateByAnyone(long relationType);
```
- 引言
- 01、开发工具
- Maven
- 术语
- 仓库
- Archetype
- 安装配置
- 典型配置
- 内置变量
- eclipse插件
- 本地包安装
- 依赖库更新
- 依赖库排错
- 常见问题
- Gradle
- build.gradle
- gradle插件
- eclipse插件
- Eclipse
- json生成bean
- 常见问题
- IDEA Community
- 工程管理
- maven操作
- 格式化
- 常见问题
- Git
- GitHub
- 快速开始
- 既有工程
- 新建工程
- 日常提交
- PR操作
- 多人协作
- 常用命令
- 常见问题
- 同步代码
- 发布库包
- CodeGenerator
- VSCode
- 安装
- 配置
- 快速开始
- 与GitHub整合
- 断点调试
- 便捷开发
- 扩展
- prettier+
- Vetur
- 前端调试
- F12调试工具
- Vue前端调试
- 测试工具
- 压力测试
- 接口测试
- 抓包工具
- 导入证书
- SecureCRT
- 02、前端技术
- 前端设计
- javascript
- 基本语法
- 数据类型
- 类型转换
- 错误处理
- console对象
- 标准库
- 异步操作
- ES6及后续增强
- 模块化
- 扩展运算符
- 解构变量
- 箭头函数
- 混入模式
- web标准
- css
- html
- HistoryApi
- dom
- 如何理解
- 虚拟dom
- JSON
- svg
- WebAssembly
- web components
- HtmlComponents
- Custom Elements
- 标准扩展
- javascript
- Babel
- TypeScript
- JavaScript
- ECMAScript
- 模块化
- CommonJS
- require
- exports与module.exports
- ES6模块
- export
- import
- AMD
- define
- require
- CMD
- define
- require
- Web Storage
- JSX
- ES6语法
- 语法糖
- ==和===
- let与const
- call&apply
- 内置对象
- Object
- Class
- Promise对象
- then
- catch
- finally
- resolve
- reject
- Module
- Generator函数
- arguments
- 函数扩展
- 数组
- 对象
- Set和Map
- Proxy对象
- css
- sass
- less
- postcss
- CSS Modules
- Node.js
- 安装
- npm
- ls
- init
- install
- run
- uninstall
- update
- version
- npm生态
- yarn
- package.json
- node_modules
- 常用技术
- 应用实例
- Web框架
- Express
- Egg.js
- Mock
- Mock.js
- 语法规范
- 非核心api
- 核心api
- easymock
- 开发测试
- ESLint
- jest
- Travis
- Prettier
- stylelint
- 构建工具
- gulp
- Browserify
- webpack
- 安装配置
- 入口起点entry
- 输出output
- 装载器loader
- 插件plugins
- webpack-cli
- public目录
- 技术概念
- CSR与SSR
- polyfill
- axios
- 请求对象
- 响应对象
- 自定义实例
- 拦截器
- 跨域访问
- 03、前端框架
- mvvm
- vue.js
- 简明指南
- vue文件结构
- 组件指南
- 组件命名
- 应用流程
- 单文件组件
- 组件导入导出
- 生命周期
- Prop
- 复用方法
- 懒加载
- 全局环境
- 全局配置
- 全局API
- 选项对象
- 混入选项
- vue实例$
- vue指令
- v-bind(:)
- v-on(@)
- v-model
- 特殊属性
- 内置组件
- 自定义机制
- 组件
- 指令
- 过滤器
- 混入
- slot插槽
- 渲染函数
- 注意事项
- 总结
- vueCli
- 安装
- 组成部分
- vue.config.js
- vue核心文件
- 状态管理
- 简单状态
- Vuex
- 构造器选项
- 实例属性
- 实例方法
- 绑定辅助函数
- 模块化
- 总结
- 路由管理
- 简单路由
- Vue Router
- 路由模式
- route
- router
- <router-link>与编程式
- <router-view>
- 嵌套路由
- 导航守卫
- 总结
- vue插件
- Vue Loader
- 实战举例
- vue快速入门
- vue与后台联动
- vue完整实例
- vue组件库
- vue-ls
- Enquire.js
- lodash
- md5.js
- moment
- nprogress
- viser-vue
- vue-clipboard2
- vue-cropper
- vue-quill-editor
- wangeditor
- vue-svg-icon-loader
- 实战参考
- Vue Antd Admin
- ant-design-vue
- 快速开始
- 要点解析
- vuepress
- vant
- 04、后端框架
- SprigBoot
- 快速入门
- 完整示例
- 完整进阶
- 核心技术
- 核心标记
- 页面技术
- Thymeleaf
- 数据访问
- 基本用法
- 事务控制
- 事务规则
- 注意事项
- 实体状态
- 数据查询
- 普通查询
- 分页查询
- 统计查询
- 命名访问
- 公用共享
- 缓存机制
- 服务层
- 控制器
- AOP
- 定时任务
- 异步任务
- 静态注入
- WebClient
- 启动机制
- 应用监控
- 线程安全
- 调试测试
- 打包部署
- 打jar包
- 常见问题
- 配置问题
- 开发问题
- 文档生成
- 相关技术
- springfox
- knife4j
- actuator
- kaptcha
- YAML
- API Blueprint
- 启用https
- SpringSecurity
- 快速入门
- 核心元素
- jwt
- 与springsecurity集成
- 05、运行容器
- artemis
- 协议支持
- mqtt
- 安装运行
- 管理配置
- 日志配置
- 业务配置
- 安全配置
- 数据存储
- SSL支持
- 运行维护
- mosquitto
- 安装运行
- 管理配置
- SSL支持
- rocketmq
- 安装运行
- 控制台
- 代码实例
- kafka
- ZooKeeper
- 安装运行
- 代码实例
- zookeeper
- 安装运行
- 应用实例
- dubbo
- 代码实例
- hadoop
- 安装配置
- 快速运行
- netty
- 06、相关技术
- Serverless
- Protobuf
- SSL
- 证书
- 认证类型
- 硬件技术
- 基础知识
- 开发技术
- 消息协议
- 07、项目实战
- 前端开发
- 从零开始开发
- 开发环境搭建
- 原生技术开发
- 路由守卫
- 动态路由菜单
- 全局API
- 登录认证
- 与后端交互
- 代码开发调试
- 快速打包发布
- 常见问题收集
- 后端开发
- 从零开始开发
- 开发环境搭建
- 常用注解说明
- 常用基础设施
- 核心业务约定
- 平台配置文件
- 业务配置清单
- 关键配置参数
- 项目必配参数
- 项目调优参数
- 返回结果处理
- 字段翻译机制
- 列表字段翻译
- 实体字段翻译
- 组合字段翻译
- 列表数据增强
- 列表数据简化
- 返回字段过滤
- 返回字段改名
- 定制返回结果
- 原生技术开发
- 动态级联字典
- 简单数据查询
- 短信验证业务
- 测试数据模拟
- 开放平台登陆
- 微信开放平台
- 抖音开放平台
- 文件处理方案
- 文件字段存储
- 文件字段解析
- 图像数据存取
- 文件资源方案
- 服务集成开发
- redis服务集成
- mqtt服务集成
- kafka集成
- rocketmq集成
- websocket集成
- elasticsearch集成
- netty集成
- 外部工具开发
- 发送短信服务
- 发送邮件服务
- 动态pdf生成
- 数据处理开发
- 同步导出数据
- 异步导出数据
- 同步导入数据
- 异步导入数据
- 多线程与并发
- 线程并发安全
- 操作间隔控制
- 异步待办机制
- 平台定时任务
- 平台异步任务
- 常见注意事项
- 安全相关开发
- 接口安全策略
- 接口限流策略
- 接口授权策略
- 权限相关开发
- 路由权限方案
- 组织权限方案
- 数据权限方案
- 字段权限方案
- 按钮权限方案
- 支付相关开发
- 微信原生支付
- 微信H5支付
- 微信JSAPI支付
- 微信批量转账
- 微信动态支付
- 支付宝移动网站支付
- 支付宝PC网站支付
- 平台缓存机制
- 内置进程内缓存
- 内置分布式缓存
- 平台自定义缓存
- 平台插件机制
- 账号的邀请码
- 账号的二维码
- 定制事件机制
- 约定实现机制
- 请求回调机制
- 启动自动加载
- 平台基础设施
- 动态参数加载
- 定制待定常量
- 定制单位组织
- 平台缓存机制
- 平台外访机制
- 静态资源获取
- 调试打印机制
- 数据源随时用
- 上下文随处拿
- 平台诊断机制
- 平台内置资源
- 强制间隔时间
- 账号扩展开发
- 账号变更事件
- 业务开发指南
- 字典数据获取
- 数据层持久化
- 基础服务调用
- 查询时间范围
- 代码开发调试
- 常见问题收集
- 从零开始
- PCV1运行
- PCV2运行
- H5端运行
- 开发进阶
- 最佳实践
- 开发方案
- 前后分离
- 跨域访问
- 库表设计
- 模型设计
- 容器部署
- 集群部署
- 日志收集
- 动态配置
- 开发管理
- 开发环境
- 代码控制
- 问题跟踪
- 进度跟踪
- 测试环境
- 调试辅助
- DevOps
- 代码风格
- 运行维护
- 基本监控知识
- 线程堆栈分析
- 内存堆栈分析
- 应用诊断工具
- 工程示范
- 后端开发
- 前端开发
- PC端
- 移动端
- 08、内置容器
- 调度服务
- 调度容器
- 快速开发
- 线程并发
- 多点部署
- 本地调试
- 常见问题
- 开放服务
- 快速接入
- 接口开发
- 09、开放平台
- 微信公号
- 环境准备
- 环境配置
- 技术方案
- 获取OpenId
- 常见问题
- 10、平台功能
- 系统管理
- 单位组织
- 角色管理
- 账号管理
- 子账号
- 财务账户
- 开放数据
- 绑定数据
- 套餐权益
- 会员定义
- 变更审核
- 注册审核
- 系统配置
- 路由配置
- 参数配置
- 属性配置
- 树形设置
- 服务接口
- 访问设置
- 系统监控
- 在线用户
- 内存数据
- 系统变量
- 外访数据
- 到访数据
- 操作记录
- 静态字典
- 日志管理
- 元数据
- 接入管理
- 微信公号
- 微信支付
- 开放服务
- 客户端
- 服务列表
- 请求历史
- 请求服务
- 调度服务
- 调度监控
- 11、补充语言
- php
- 生产环境
- 安装
- 初始配置
- nginx集成
- 配置文件
- 语法
- 变量和常量
- 数据类型
- 条件控制
- 运算符
- 数组
- 指针
- 循环控制
- 函数
- 语法糖
- 预定义变量
- session和cookie
- 命名空间
- 面向对象
- 数据库操作
- 表单
- 错误
- 异常
- 过滤器
- JSON
- XML
- AJAX
- Composer
- 开发环境
- 本地调试
- 远程调试
- .net
- 开发环境
- C#快速入门
- 12、依赖容器
- elasticsearch
- 运行配置
- 命令操作
- 中文分词
- Kibana
- Logstash
- 开发技术
- 搜索类型
- 代码示例
- 应用场景
- 常见问题
- nginx
- 下载安装
- 基本配置
- 服务启停
- 安全防护
- 常见问题
- linux
- 常用操作
- 常用命令
- 用户管理
- ftp服务
- 防火墙
- 运维
- 网络安全
- 内核参数
- 安装
- yum源问题
- mysql
- 安装配置
- 快速安装
- 正式安装
- 参数配置
- 性能优化
- 语句优化
- 配置优化
- 设计优化
- 运维常识
- 系统监控
- 连接数
- 超时
- cpu利用率
- 数据备份
- 导入复制
- 经验举例
- 故障处理
- 用户管理
- 系统日志
- 日志清理
- 安全经验
- 集群方案
- MySQL Replication
- MySQL Cluster
- 常见问题
- redis
- 安装配置
- 安装运行
- 参数配置
- 运维常识
- 技术要点
- pubSub
- 操作命令
- 持久化
- 常见问题
- docker
- 安装运行
- 镜像操作
- 容器操作
- 仓库操作
- 实战案例
- kubernetes
- 后记