整合HikariCP
- pom中引入数据源驱动与mybatis依赖
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
- 在yml中配置数据源和mybatis
############################################################
#
# 配置数据源信息
#
############################################################
spring:
datasource: # 数据源的相关配置
type: com.zaxxer.hikari.HikariDataSource # 数据源类型:HikariCP
driver-class-name: com.mysql.jdbc.Driver # mysql驱动
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: root
password: root
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
minimum-idle: 5 # 最小连接数
maximum-pool-size: 20 # 最大连接数
auto-commit: true # 自动提交
idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
pool-name: DateSourceHikariCP # 连接池名字
max-lifetime: 1800000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
connection-test-query: SELECT 1
############################################################
#
# mybatis 配置
#
############################################################
mybatis:
type-aliases-package: com.tolman.pojo # 所有POJO类所在包路径
mapper-locations: classpath:mapper/*.xml # mapper映射文件
- 内置tomcat
############################################################
#
# web访问端口号 约定:8088
#
############################################################
server:
port: 8088
tomcat:
uri-encoding: UTF-8
max-http-header-size: 80KB
通用Mapper接口所封装的常用方法
- 首先先来看一下
MyMapper
所继承的父类,如:
interface MyMapper<T> extends Mapper<T>,MySqlMapper<T>
这里有两个父类,Mapper<T>
与MySqlMapper<T>
,我们可以打开MySqlMapper<T>
看一下:
interface MySqlMapper<T> extends InsertListMapper<T>,InsertUseGeneratedKeysMapper<T>{}
这里面又继承了了两个mapper,从类名上可以看得出来,是用于操作数据库的,这两个类里又分别包含了如下方法,简单归类一下:
方法名 | 操作 | 备注 |
---|---|---|
insertList(list) | 数据批量插入 | 主键须自增 |
insertUseGeneratedKeys(record) | 插入表数据 | 主键须自增 |
很明显,在传统JavaWeb开发,这两个方法使用是没有问题的,但是我们的数据库表主键设计肯定是全局唯一的,所以不可能使用自增长id,所以这两个方法在我们开发过程中是不会使用的!
- 随后再来看一下
Mapper<T>
中所继承的父类,如下:
interface Mapper<T> extends BaseMapper<T>,ExampleMapper<T>,RowBoundsMapper<T>,
分别来看一下各个父类中的方法有些啥?
BaseMapper<T>
类 | 方法 | 操作 |
---|---|---|
BaseSelectMapper | T selectOne(T record) | 根据实体类中的属性查询表数据,返回单个实体 |
List select(T record) | 根据实体类中的属性查询表数据,返回符合条件的list | |
List selectAll() | 返回该表所有记录 | |
int selectCount(T record) | 根据条件查询记录数 | |
T selectByPrimaryKey(Object key) | 根据主键查询单挑记录 | |
boolean existsWithPrimaryKey(Object key) | 查询主键是否存在,返回true或false | |
BaseInsertMapper | int insert(T record) | 插入一条记录,属性为空也会保存 |
int insertSelective(T record) | 插入一条记录,属性为空不保存,会使用默认值 | |
BaseUpdateMapper | int updateByPrimaryKey(T record) | 根据实体类更新数据库,属性有null会覆盖原记录 |
int updateByPrimaryKeySelective(T record) | 根据实体类更新数据库,属性有null改属性会忽略 | |
BaseDeleteMapper | int delete(T record) | 根据实体类中属性多条件删除记录 |
int deleteByPrimaryKey(Object key) | 根据主键删除记录 |
ExampleMapper<T>
,Example类是用于提供给用户实现自定义条件的,也就是where
条件,主要方法见如下表格:
类 | 方法 | 操作 |
---|---|---|
SelectByExampleMapper | List selectByExample(Object example) | 根据条件查询记录list |
SelectOneByExampleMapper | T selectOneByExample(Object example) | 根据条件查询单条记录 |
SelectCountByExampleMapper | int selectCountByExample(Object example) | 根据条件查询记录数 |
DeleteByExampleMapper | int deleteByExample(Object example) | 根据条件删除记录 |
UpdateByExampleMapper | int updateByExample(T record, @Param(“example”) Object example); | 根据条件更新数据,null会覆盖原数据 |
UpdateByExampleSelectiveMapper | int updateByExampleSelective(T record, Object example); | 根据条件更新数据,null会忽略 |
RowBoundsMapper<T>
,这个是用于做分页的,我们在后续阶段中会使用page-helper这个组件来替代这个分页实现。
总结
通用mapper所提供的CRUD方法对单表操作,大大提高开发效率,当然复杂的多表操作还是需要在mapper.xml中自己去编写sql代码实现。
事务传播
事务传播 - Propagation
-
REQUIRED: 使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;如果当前存在事务,则加入这个事务,成为一个整体
-
SUPPORTS: 如果当前有事务,则使用事务;如果当前没有事务,则不使用事务
-
MANDATORY: 该传播属性强制必须存在一个事务,如果不存在,则抛出异常
-
REQUIRES_NEW: 如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用,如果当前没有事务,则同 REQUIRED
-
NOT_SUPPORTED: 如果当前有事务,则把事务挂起,自己不适用事务去运行数据库操作
-
NEVER: 如果当前有事务存在,则抛出异常
-
NESTED: 如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;
如果当前没有事务,则同 REQUIRED。但是如果主事务提交,则会携带子事务一起提交。
如果主事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚
Cookie和Session
Cookie
- 以键值对的形式存储信息在浏览器
- cookie不能跨域,当前及其父级域名可以取值
Session
- 基于服务器内存的缓存(非持久化),可保持请求会话
- 每个session通过sessionid来区分不同请求
- session可设置过期时间
- session也是一键值对形式存在的
Swagger2文档API
- 配置依赖
<!-- swagger2 配置 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.6</version>
</dependency>
http://localhost:8088/swagger-ui.html
http://localhost:8088/doc.html
SpringBoot Log日志
SpringBoot 日志
- 移除默认日志
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
- 添加日志框架依赖
<!--引入日志依赖 抽象层 与 实现层-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
- 创建log4j.properties并且放到资源文件目录src/main/resources
log4j.rootLogger=DEBUG,stdout,file
log4j.additivity.org.apache=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.DatePattern='.'yyyy-MM-dd-HH-mm
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file.Threshold=INFO
log4j.appender.file.append=true
log4j.appender.file.File=/workspaces/logs/foodie-api/mylog.log
public static final Logger logger =
LoggerFactory.getLogger(ServiceLogAspect.class);
if (takeTime > 3000) {
logger.error("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else if (takeTime > 2000) {
logger.warn("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else {
logger.info("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
}
通过日志监控service执行时间
- 添加切面依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 编写AOP类ServiceLogAspect
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ServiceLogAspect {
public static final Logger logger =
LoggerFactory.getLogger(ServiceLogAspect.class);
/**
* AOP通知:
* 1. 前置通知:在方法调用之前执行
* 2. 后置通知:在方法正常调用之后执行
* 3. 环绕通知:在方法调用之前和之后,都分别可以执行的通知
* 4. 异常通知:如果在方法调用过程中发生异常,则通知
* 5. 最终通知:在方法调用之后执行
*/
/**
* 切面表达式:
* execution 代表所要执行的表达式主体
* 第一处 * 代表方法返回类型 *代表所有类型
* 第二处 包名代表aop监控的类所在的包
* 第三处 .. 代表该包以及其子包下的所有类方法
* 第四处 * 代表类名,*代表所有类
* 第五处 *(..) *代表类中的方法名,(..)表示方法中的任何参数
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* com.tolman.service.impl..*.*(..))")
public Object recordTimeLog(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("====== 开始执行 {}.{} ======",
joinPoint.getTarget().getClass(),
joinPoint.getSignature().getName());
// 记录开始时间
long begin = System.currentTimeMillis();
// 执行目标 service
Object result = joinPoint.proceed();
// 记录结束时间
long end = System.currentTimeMillis();
long takeTime = end - begin;
if (takeTime > 3000) {
logger.error("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else if (takeTime > 2000) {
logger.warn("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
} else {
logger.info("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
}
return result;
}
}
开启MyBatis日志Sql打印
- 修改配置文件application.yml
mybatis:
type-aliases-package: com.tolman.pojo # 所有POJO类所在包路径
mapper-locations: classpath:mapper/*.xml # mapper映射文件
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
SpringBoot 整合 mybatis-pagehelper
- 引入分页插件依赖
<!--pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
- 配置yml
# 分页插件配置
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
- 使用分页插件,在查询前使用分页插件,原理:统一拦截sql,为其提供分页功能
/**
* page: 第几页
* pageSize: 每页显示条数
*/
PageHelper.startPage(page, pageSize);
- 分页数据封装到
PagedGridResult.java
传给前端
PageInfo<?> pageList = new PageInfo<>(list);
PagedGridResult grid = new PagedGridResult();
grid.setPage(page);
grid.setRows(list);
grid.setTotal(pageList.getPages());
grid.setRecords(pageList.getTotal());
Nginx核心配置
-
设置worker进程的用户,指的linux中的用户,会涉及到nginx操作目录或文件的一些权限,默认为
nobody
user root;
-
worker进程工作数设置,一般来说CPU有几个,就设置几个,或者设置为N-1也行
worker_processes 1;
-
nginx 日志级别
debug | info | notice | warn | error | crit | alert | emerg
,错误级别从左到右越来越大 -
设置nginx进程 pid
pid logs/nginx.pid;
-
设置工作模式
events { # 默认使用epoll use epoll; # 每个worker允许连接的客户端最大连接数 worker_connections 10240; }
-
http 是指令块,针对http网络传输的一些指令配置
http { }
-
include 引入外部配置,提高可读性,避免单个配置文件过大
include mime.types;
-
设定日志格式,
main
为定义的格式名称,如此 access_log 就可以直接使用这个变量了
参数名 参数意义 $remote_addr 客户端ip $remote_user 远程客户端用户名,一般为:’-’ $time_local 时间和时区 $request 请求的url以及method $status 响应状态码 $body_bytes_send 响应客户端内容字节数 $http_referer 记录用户从哪个链接跳转过来的 $http_user_agent 用户所使用的代理,一般来时都是浏览器 $http_x_forwarded_for 通过代理服务器来记录客户端的ip -
sendfile
使用高效文件传输,提升传输性能。启用后才能使用tcp_nopush
,是指当数据表累积一定大小后才发送,提高了效率。sendfile on; tcp_nopush on;
-
keepalive_timeout
设置客户端与服务端请求的超时时间,保证客户端多次请求的时候不会重复建立新的连接,节约资源损耗。#keepalive_timeout 0; keepalive_timeout 65;
-
gzip
启用压缩,html/js/css压缩后传输会更快gzip on;
-
server
可以在http
指令块中设置多个虚拟主机- listen 监听端口
- server_name localhost、ip、域名
- location 请求路由映射,匹配拦截
- root 请求位置
- index 首页设置
server { listen 88; server_name localhost; location / { root html; index index.html index.htm; } }
// TODO