用户和综合分析系统
项目背景
近年来,伴随着互联网金融的风生水起;国家出台相关文件,要求加大互联网交易风险防控力度;鼓励通过大数据分析、用户行为建模等手段建立和完善交易风险检测模型。但是目前大数据风控还存在时效性差,准确性不高等问题。综合用户分析平台包含 综合数据分析|登陆风险|注册风险|交易风险|活动风险分析等模块。以下是个各个子系统之间的关系。
- 业务系统:通常指的是APP+后台或Web端(服务目标用户),是业务模块的载体,大数据计算的数据来源。
- 风控系统(流计算):为业务系统提供支持(服务目标是后台服务),根据业务系统搜集来得数据数据或者在页面埋藏的一些
埋点
去获取用户使用环境或者用户操作行为。 - 惩罚系统:根据风险评估系统计算出的
报告
、根据报告配合具体的惩罚业务对事件产生者进行控制或者惩罚。例如:增加验证码、禁止用户登录、注册或者下单。 - 综合分析: 辅助风控系统,根据分控系统的表现,判断的风控的策略或者参数设置是否存在问题。比如:评估因子触发率极低或者极高等,该系统的可以有效的帮助的运营和分析人员完成新策略的发现以及营销手段改良。
平台架构
系统模型
实时业务
注册风险
检测出一些不正常的注册行为,并产生注册评估报告。
- 短时间内同一个设备在同一个网络下注册数据超过N个
- 如果注册时间少于m分钟,且产生多次注册行为,认定注册有异常.
- 同一个设备或者IP,规定时间内多次调用
短信
|邮件服务
超过N次 ,注册风险
√登录风险
检查出非用户登录,或者账号被盗窃等潜在风险挖掘。
- 异地登录认定有风险(不在用户经常登陆地)
- 登录的位移速度超过正常值,认定有风险
- 更换设备,认定有风险
- 登录时段-习惯,出现了异常,存在风险
- 每天的累计登录次数超过上限,认定有风险
- 密码输入错误或者输入差异性较大,认定风险
- 如果用户的输入特征(输入每个控件所需时长 ms)发生变化
交易风险
辅助系统检测用户支付环境,地区、网络、次数
- 用户交易习惯,出现在异常时段认定有异常
- 检测用户的网络环境,如果不是经常使用WI-FI
- 短时间内产生多次交易,存在风险
- 支付金额过大,认定有风险
- 陌生地区支付,认定有风险
- 交易设备发生变化
活动风险
活动风险涉及活动时间、奖励兑换/兑换率
- 活动时间提前结束,认定有风险。
- 活动短时间内兑换率过高。
- 一个账号多次兑换认定有风险。
离线业务
辅助流计算或者企业运营部更好经营业务。
分析平台用户成分(性别、设备、年龄段、地域)
应用使用习惯(时间、类别|频道)
频道或者类别点击排行榜,页面停留时长、跳出率
风控系统中各类评估因子在每个应用的应用表现
Java业务板块 (阶段1)
工作计划表
任务计划 | 工时安排 | 备注 |
---|---|---|
SpringBoot快速构建Web-Model后端 Restful 接口发布 | 1天-编码 | |
RestTemplate、WebClient/Postman 单元测试 | 1天-讲解 | |
基于EasyUI对接Restful接口完成前后端对接 | 3天-70%讲解、30%实战 | |
jQuery插件定制和和埋点设计 | 0.5天-100%讲解 | |
jQuery自定义插件和和埋点设计 | 1.5天-70%讲解、30%实战 | |
Echars/HighCharts基础报表可视化展示(静态) | 1.5天-30%讲解、70%实战 | |
对接SpringCloud完成微服务的开发与部署 | 3天- 70%讲解 30%实战 |
Notes:辅线,不会涉及Java中过多复杂业务场景,仅仅作为JavaWeb业务基础,用于展示大数据可视化平台,以及了解什么是微服务开发。
SpringBoot快速构建Web-User-Model后端 Restful 接口发布
<groupId>com.baizhi</groupId>
<artifactId>UserModel</artifactId>
<version>1.0-SNAPSHOT</version>
1、要求SpringBoot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
2、给出以下脚本
DROP TABLE IF EXISTS t_user;
set character_set_results=utf8;
set character_set_client=utf8;
CREATE TABLE t_user (
id int primary key AUTO_INCREMENT,
name varchar(32) unique ,
password varchar(128) ,
sex tinyint(1) ,
photo varchar(255) ,
birthDay date,
email varchar(128)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8;
3、实体类
public class User implements Serializable {
private Integer id;
private String name;
private boolean sex;
private String password;
private Date birthDay;
private String photo;
private String email;
...
}
4、DAO接口
public interface IUserDAO {
void saveUser(User user);
User queryUserByNameAndPassword(User user);
User queryUserById(Integer id);
void deleteByUserId(Integer id);
List<User> queryUserByPage(
@Param(value = "pageNow") Integer pageNow,
@Param(value = "pageSize") Integer pageSize,
@Param(value = "column") String column,
@Param(value = "value") Object value);
int queryCount(
@Param(value = "column") String column,
@Param(value = "value") Object value);
void updateUser(User user);
}
5、Service接口
public interface IUserService {
/**
* 保存用户
* @param user
*/
void saveUser(User user);
/**
* 根据密码和用户名查询用户
* @param user
* @return
*/
User queryUserByNameAndPassword(User user);
/***
*
* @param pageNow
* @param pageSize
* @param column 模糊查询列
* @param value 模糊值
* @return
*/
List<User> queryUserByPage(Integer pageNow, Integer pageSize,
String column, Object value);
/**
* 查询用户总记录
* @param column
* @param value
* @return
*/
int queryUserCount(String column, Object value);
/**
* 根据ID查询用户信息
* @param id
* @return
*/
User queryUserById(Integer id);
/**
* 根据IDS删除用户
* @param ids
*/
void deleteByUserIds(Integer[] ids);
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
}
6、控制层访问接口
@RestController
@RequestMapping(value = "/formUserManager")
public class FormUserController {
@PostMapping(value = "/registerUser")
public User registerUser(User user,
@RequestParam(value = "multipartFile",required = false) MultipartFile multipartFile) throws IOException
@PostMapping(value = "/userLogin")
public User userLogin(User user)
@PostMapping(value = "/addUser")
public User addUser(User user,
@RequestParam(value = "multipartFile",required = false) MultipartFile multipartFile) throws IOException
@PutMapping(value = "/updateUser")
public void updateUser(User user,
@RequestParam(value = "multipartFile",required = false) MultipartFile multipartFile) throws IOException
@DeleteMapping(value = "/deleteUserByIds")
public void delteUserByIds(@RequestParam(value = "ids") Integer[] ids)
@GetMapping(value = "/queryUserByPage")
public List<User> queryUserByPage(@RequestParam(value = "page",defaultValue = "1") Integer pageNow,
@RequestParam(value = "rows",defaultValue = "10") Integer pageSize,
@RequestParam(value = "column",required = false) String column,
@RequestParam(value = "value",required = false) String value)
@GetMapping(value = "/queryUserCount")
public Integer queryUserCount( @RequestParam(value = "column",required = false) String column,
@RequestParam(value = "value",required = false) String value)
@GetMapping(value = "/queryUserById")
public User queryUserById(@RequestParam(value = "id") Integer id)
}
构建项目
项目基本结构
配置⽂件清单
- maven pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baizhi</groupId>
<artifactId>UserModel</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>UserModel Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<!-- 仲裁中心 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- msq -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!-- 阿里连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.3</version>
</dependency>
<!-- 使内嵌的tomcat支持解析jsp -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
<scope>compile</scope>
</dependency>
<!-- 文件支持 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<!-- lombok相关 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!--Spring Redis RedisAutoConfiguration-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
<build>
<finalName>UserModel</finalName>
<plugins>
<!-- springbootjar包支持 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
- application.yml
# 访问接口配置
server:
port: 8989
servlet:
context-path: /UserModel
spring:
# 数据源配置
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://CentOS:3306/usermodel?useSSL=false&characterEncoding=UTF8&serverTimezone=GMT
# 上传文件控制
servlet:
multipart:
max-request-size: 50MB
max-file-size: 50MB
enabled: true
# 乱码解决
http:
encoding:
charset: utf-8
# 连接redis
redis:
host: CentOS
port: 6379
# Mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.baizhi.entity
# //在resource目录下建立config文件夹
config-location: classpath:config/mybatis.xml
# 开启Mybatis批处理模式
logging:
level:
root: info
- UserDAO.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baizhi.dao.IUserDAO">
<cache type="com.baizhi.cache.UserDefineRedisCache"></cache>
<sql id="all">
id, name, password, sex, photo, birthDay, email
</sql>
<resultMap type="com.baizhi.entity.User" id="TUserMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="sex" column="sex" jdbcType="OTHER"/>
<result property="photo" column="photo" jdbcType="VARCHAR"/>
<result property="birthDay" column="birthDay" jdbcType="OTHER"/>
<result property="email" column="email" jdbcType="VARCHAR"/>
</resultMap>
<!--查询单个-->
<select id="queryUserById" resultMap="TUserMap">
select
<include refid="all"></include>
from usermodel.t_user
where id = #{id}
</select>
<!--查询指定行数据-->
<select id="queryUserByPage" resultMap="TUserMap">
select <include refid="all"></include> from usermodel.t_user
<where>
<if test="column != null and column != '' and value != ''">
${column} like "%"#{value}"%"
</if>
</where>
limit #{pageNow},#{pageSize}
</select>
<!--通过姓名密码筛选条件查询-->
<select id="queryUserByNameAndPassword" resultMap="TUserMap">
select
<include refid="all"></include>
from usermodel.t_user
<where>
<if test="name != null and name != ''">
and name = #{name}
</if>
<if test="password != null and password != ''">
and password = #{password}
</if>
</where>
</select>
<!--添加用户-->
<insert id="saveUser" keyProperty="id" useGeneratedKeys="true">
insert into usermodel.t_user(name, password, sex, photo, birthDay, email)
values (#{name}, #{password}, #{sex}, #{photo}, #{birthDay}, #{email})
</insert>
<!--修改数据-->
<update id="updateUser">
update usermodel.t_user
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="sex != null">
sex = #{sex},
</if>
<if test="photo != null and photo != ''">
photo = #{photo},
</if>
<if test="birthDay != null">
birthDay = #{birthDay},
</if>
<if test="email != null and email != ''">
email = #{email},
</if>
</set>
where id = #{id}
</update>
<!--通过主键删除-->
<delete id="deleteByUserId">
delete from usermodel.t_user where id = #{id}
</delete>
<!-- 查询总行数 -->
<select id="queryCount" resultType="Integer">
select count(*) from t_user
<where>
<if test="column != null and column != '' and value != ''">
${column} like "%"#{value}"%"
</if>
</where>
</select>
</mapper>
- logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%p %c#%M %d{yyyy-MM-dd HH:mm:ss} %m%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/userLoginFile-%d{yyyyMMdd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%p %c#%M %d{yyyy-MM-dd HH:mm:ss} %m%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 控制台输出⽇志级别 -->
<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.springframework.jdbc" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com.baizhi.dao" level="TRACE" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com.baizhi.cache" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
</configuration>
- t_user.sql
DROP TABLE IF EXISTS t_user;
set character_set_results=utf8;
set character_set_client=utf8;
CREATE TABLE t_user (
id int primary key AUTO_INCREMENT,
name varchar(32) unique ,
password varchar(128) ,
sex tinyint(1) ,
photo varchar(255) ,
birthDay date,
email varchar(128)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8;
项⽬代码清单
- User实体类
/**
* (TUser)实体类
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 250284593728595695L;
private Integer id;
private String name;
private boolean sex;
private String password;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date birthDay;
private String photo;
private String email;
}
- Dao接口
/**
* (TUser)DAO接口
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
public interface IUserDAO {
/**
* 添加用户信息
*
* @param user
*/
void saveUser(User user);
/**
* 根据用户名称及密码查询用户
*
* @param user
* @return
*/
User queryUserByNameAndPassword(User user);
/**
* 根基用户ID查询
*
* @param id
* @return
*/
User queryUserById(Integer id);
/**
* 删除用户
*
* @param id
*/
void deleteByUserId(Integer id);
/**
* 分页查询用户
*
* @param pageNow
* @param pageSize
* @param column
* @param value
* @return
*/
List<User> queryUserByPage(
@Param(value = "pageNow") Integer pageNow,
@Param(value = "pageSize") Integer pageSize,
@Param(value = "column") String column,
@Param(value = "value") Object value);
/**
* 查询总行数
*
* @param column
* @param value
* @return
*/
int queryCount(
@Param(value = "column") String column,
@Param(value = "value") Object value);
/**
* 修改用户信息
*
* @param user
*/
void updateUser(User user);
}
- Service接口
/**
* (TUser)表服务接口
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
public interface IUserService {
/**
* 添加用户
*
* @param user
*/
void saveUser(User user);
/**
* 根据密码和用户名查询用户
*
* @param user
* @return
*/
User queryUserByNameAndPassword(User user);
/***
*
* @param pageNow
* @param pageSize
* @param column 模糊查询列
* @param value 模糊值
* @return
*/
List<User> queryUserByPage(Integer pageNow, Integer pageSize,
String column, Object value);
/**
* 查询用户总记录
*
* @param column
* @param value
* @return
*/
int queryUserCount(String column, Object value);
/**
* 根据ID查询用户信息
*
* @param id
* @return
*/
User queryUserById(Integer id);
/**
* 根据IDS删除用户
*
* @param ids
*/
void deleteByUserIds(Integer[] ids);
/**
* 更新用户信息
*
* @param user
*/
void updateUser(User user);
}
- Service实现类
/**
* (TUser)表服务实现类
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
@Service("tUserService")
@Transactional
public class IUserServiceImpl implements IUserService {
@Resource
private IUserDAO iUserDAO;
/**
* 添加用户
*
* @param user
*/
@Override
public void saveUser(User user) {
iUserDAO.saveUser(user);
}
/**
* 根据条件查询
*
* @param user
* @return
*/
@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public User queryUserByNameAndPassword(User user) {
User user1 = iUserDAO.queryUserByNameAndPassword(user);
return user1;
}
/**
* 分页查询
*
* @param pageNow
* @param pageSize
* @param column 模糊查询列
* @param value 模糊值
* @return
*/
@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public List<User> queryUserByPage(Integer pageNow, Integer pageSize, String column, Object value) {
int i = pageNow - 1;
int i1 = i * pageSize;
List<User> users = iUserDAO.queryUserByPage(i1, pageSize, column, value);
return users;
}
/**
* 统计总行数
*
* @param column
* @param value
* @return
*/
@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public int queryUserCount(String column, Object value) {
int count = iUserDAO.queryCount(column, value);
return count;
}
/**
* 根据ID查询用户
*
* @param id
* @return
*/
@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public User queryUserById(Integer id) {
User user = iUserDAO.queryUserById(id);
return user;
}
/**
* 删除用户
*
* @param ids
*/
@Override
public void deleteByUserIds(Integer[] ids) {
for (Integer id : ids) {
iUserDAO.deleteByUserId(id);
}
}
/**
* 修改用户信息
*
* @param user
*/
@Override
public void updateUser(User user) {
iUserDAO.updateUser(user);
}
}
- Application-springboot入口类
package com.baizhi;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
@SpringBootApplication
@MapperScan(basePackages = "com.baizhi.dao")
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
@Bean
public RedisTemplate redisTemplate() {
return new RedisTemplate();
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
集成Junit测试
- 创建测试配置类
- Dao测试
/**
* UserDao测试类
*/
@RunWith(value = SpringRunner.class)
@SpringBootTest
@Slf4j
public class UserDaoTest {
@Resource
private IUserDAO iUserDAO;
@Test
public void queryById() {
System.out.println(iUserDAO.queryUserById(3));
}
@Test
public void queryAll() {
List<User> users = iUserDAO.queryUserByPage(0, 3, "name", "z");
for (User user : users) {
System.out.println(user);
}
}
@Test
public void addUser() {
User user = new User();
user.setName("张三");
user.setPassword("123123");
Date date = new Date();
user.setBirthDay(date);
iUserDAO.saveUser(user);
}
@Test
public void twoCacheTest() {
User user1 = iUserDAO.queryUserById(1);
log.info("user1:{}", JSON.toJSONString(user1));
log.info("第一次查询");
User user2 = iUserDAO.queryUserById(1);
log.info("user2:{}", JSON.toJSONString(user2));
log.info("第二次查询");
User user3 = iUserDAO.queryUserById(1);
log.info("user3:{}", JSON.toJSONString(user3));
log.info("第三次查询");
user1.setName("test1");
iUserDAO.updateUser(user1);
User user4 = iUserDAO.queryUserById(1);
log.info("user4:{}", JSON.toJSONString(user4));
log.info("第四次查询");
}
}
- Service测试
package com.baizhi.service;
import com.baizhi.entity.User;
import com.baizhi.service.impl.IUserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.*;
/**
* UserService测试类
*/
@RunWith(value = SpringRunner.class)
@SpringBootTest
@Slf4j
public class UserServiceTest {
@Autowired
private IUserService userService;
@Test
public void saveUserTest() {
User user = new User(null, "赵⼩六", true, "123456", new Date(), "aa.png", "qq.com");
userService.saveUser(user);
assertNotNull("⽤户ID不为空", user.getId());
}
@Test
public void queryUserByNameAndPasswordTests() {
User loginUser = new User();
loginUser.setName("赵⼩六");
loginUser.setPassword("123456");
User queryUser = userService.queryUserByNameAndPassword(loginUser);
assertNotNull("⽤户ID不为空", queryUser.getId());
}
@Test
public void queryUserByPageTests() {
Integer pageNow = 1;
Integer pageSize = 10;
String column = "name";
String value = "⼩";
List<User> userList = userService.queryUserByPage(pageNow, pageSize, column,
value);
assertFalse(userList.isEmpty());
}
@Test
public void queryUserCountTest() {
String column = "name";
String value = "⼩";
Integer count = userService.queryUserCount(column, value);
assertTrue(count != 0);
}
@Test
public void queryUserById() {
Integer id = 2;
User u = userService.queryUserById(id);
assertNotNull(u.getName());
}
@Test
public void deleteByUserIdsTests() {
userService.deleteByUserIds(new Integer[]{1, 4, 3});
}
@Test
public void updateUserTests() {
Integer id = 2;
User u = userService.queryUserById(id);
assertNotNull(u.getName());
u.setSex(false);
userService.updateUser(u);
User newUser = userService.queryUserById(2);
assertEquals("⽤户sex", false, newUser.getSex());
}
}
Notes:这⾥使⽤Junit测试的Assert(断⾔测试),需要额外的导⼊ import static org.junit.Assert.*;
RestControler发布与测试
RestControler
- form表单参数接收
/**
* (TUser)表控制层
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
@RestController
@RequestMapping(value = "/formUserManager")
public class FormUserController {
private static final Logger LOGGER = LoggerFactory.getLogger(FormUserController.class);
@Autowired
private IUserServiceImpl tUserService;
/**
* 用户登陆
*
* @param user
* @return
*/
@PostMapping(value = "/userLogin")
public User userLogin(User user) {
return tUserService.queryUserByNameAndPassword(user);
}
/**
* 添加用户
*
* @param user
* @param multipartFile
* @return
* @throws IOException
*/
@PostMapping(value = "/addUser")
public User addUser(User user, @RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile) throws IOException {
if (multipartFile != null) {
String filename = multipartFile.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf("."));
File tempFile = File.createTempFile(filename.substring(0, filename.lastIndexOf(".")), suffix);
System.out.println(tempFile.getName());
tempFile.delete();
}
tUserService.saveUser(user);
return user;
}
/**
* 修改用户信息
*
* @param user
* @param multipartFile
* @throws IOException
*/
@PutMapping(value = "/updateUser")
public void updateUser(User user, @RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile) throws IOException {
if (multipartFile != null) {
String filename = multipartFile.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf("."));
File tempFile = File.createTempFile(filename.substring(0, filename.lastIndexOf(".")), suffix);
System.out.println(tempFile.getName());
tempFile.delete();
}
//更新用户信息
tUserService.updateUser(user);
}
/**
* 删除用户
*
* @param ids
*/
@DeleteMapping(value = "/deleteUserByIds")
public void delteUserByIds(@RequestParam(value = "ids") Integer[] ids) {
tUserService.deleteByUserIds(ids);
}
/**
* 模糊查询
*
* @param pageNow
* @param pageSize
* @param column
* @param value
* @return
*/
@GetMapping(value = "/queryUserByPage")
public List<User> queryUserByPage(@RequestParam(value = "page", defaultValue = "1") Integer pageNow,
@RequestParam(value = " ", defaultValue = "10") Integer pageSize,
@RequestParam(value = "column", required = false) String column,
@RequestParam(value = "value", required = false) String value) {
HashMap<String, Object> map = new HashMap<>();
map.put("total", tUserService.queryUserCount(column, value));
map.put("rows", tUserService.queryUserByPage(pageNow, pageSize, column, value));
return tUserService.queryUserByPage(pageNow, pageSize, column, value);
}
/**
* 统计总人数
*
* @param column
* @param value
* @return
*/
@GetMapping(value = "/queryUserCount")
public Integer queryUserCount(@RequestParam(value = "column", required = false) String column,
@RequestParam(value = "value", required = false) String value) {
return tUserService.queryUserCount(column, value);
}
/**
* 根据ID查询用户
*
* @param id
* @return
*/
@GetMapping(value = "/queryUserById")
public User queryUserById(@RequestParam(value = "id") Integer id) {
//从数据库中查询
return tUserService.queryUserById(id);
}
}
- json格式数据接收
/**
* (TUser)表控制层-JSON方式提交
*
* @author makejava
* @since 2020-03-16 16:54:52
*/
@RestController
@RequestMapping(value = "/restUserManager")
public class RestUserController {
private static Logger logger = LoggerFactory.getLogger(RestUserController.class);
@Autowired
private IUserServiceImpl iUserService;
/**
* 用户登陆
*
* @param user
* @return
*/
@PostMapping(value = "userLogin")
public User userLogin(@RequestBody User user) {
return iUserService.queryUserByNameAndPassword(user);
}
/**
* 注册用户
*
* @param user
* @param multipartFile
* @return
* @throws IOException
*/
@PostMapping(value = "addUser")
public User addUser(@RequestPart(value = "user") User user, @RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile) throws IOException {
//判断上传的文件是否为空
if (multipartFile != null) {
//获取文件的原始名
String filename = multipartFile.getOriginalFilename();
//获取文件类型
String substring = filename.substring(filename.lastIndexOf("."));
//创建临时文件
File tempFile = File.createTempFile(filename.substring(0, filename.lastIndexOf(".")), substring);
//打印临时文件名
System.out.println(tempFile.getName());
//删除临时文件名
tempFile.delete();
}
iUserService.saveUser(user);
return user;
}
public void updataUser(@RequestPart(value = "user") User user, @RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile) throws IOException {
//判断上传的文件是否为空
if (multipartFile != null) {
//获取文件的原始名
String filename = multipartFile.getOriginalFilename();
//获取文件类型
String substring = filename.substring(filename.lastIndexOf("."));
//创建临时文件
File tempFile = File.createTempFile(filename.substring(0, filename.lastIndexOf(".")), substring);
//打印临时文件名
System.out.println(tempFile.getName());
//删除临时文件名
tempFile.delete();
}
//修改用户信息
iUserService.updateUser(user);
}
/**
* 删除用户
*
* @param ids
*/
@DeleteMapping(value = "deleteUserByIds")
public void deleteUserByIds(@RequestParam(value = "ids") Integer[] ids) {
iUserService.deleteByUserIds(ids);
}
/**
* 根据id查一个
*
* @param id
* @return
*/
@GetMapping(value = "queryById")
public User queryById(@RequestParam(value = "id") Integer id) {
return iUserService.queryUserById(id);
}
/**
* 模糊分页查询
*
* @param pageNow
* @param pageSize
* @param column
* @param value
* @return
*/
@GetMapping(value = "/queryUserByPage")
public List<User> queryUserByPage(@RequestParam(value = "page", defaultValue = "1")
Integer pageNow,
@RequestParam(value = "rows", defaultValue =
"10") Integer pageSize,
@RequestParam(value = "column", required = false)
String column,
@RequestParam(value = "value", required = false)
String value) {
HashMap<String, Object> results = new HashMap<>();
results.put("total", iUserService.queryUserCount(column, value));
results.put("rows", iUserService.queryUserByPage(pageNow, pageSize, column, value));
return iUserService.queryUserByPage(pageNow, pageSize, column, value);
}
/**
* 统计总人数
*
* @param column
* @param value
* @return
*/
@GetMapping(value = "/queryUserCount")
public Integer queryUserCount(@RequestParam(value = "column", required = false) String column,
@RequestParam(value = "value", required = false) String value) {
return iUserService.queryUserCount(column, value);
}
}
RestTemplate
- FormUserControllerTests
/**
* controller测试类
*/
@SpringBootTest(classes = {Application.class})
@RunWith(SpringRunner.class)
public class FormUserControllerTests {
@Resource
private RestTemplate restTemplate;
private String urlPrefix = "http://127.0.0.1:8888/formUserManager";
/*
@PostMapping(value = "/registerUser")
public User registerUser(User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile)
*/
@Test
public void testRegisterUser() {
String url = urlPrefix + "/registerUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("name", "李⼩四");
formData.add("password", "123456");
formData.add("sex", "true");
formData.add("birthDay", "2018-01-26");
formData.add("photo", "user.png");
formData.add("email", "[email protected]");
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
User user = restTemplate.postForObject(url, formData, User.class);
assertNotEquals("⽤户ID", user.getId());
}
/*
@PostMapping(value = "/userLogin")
public User userLogin(User user)
*/
@Test
public void testUserLogin() {
String url = urlPrefix + "/userLogin";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>
();
formData.add("name", "李⼩四");
formData.add("password", "123456");
User user = restTemplate.postForObject(url, formData, User.class);
assertNotEquals("⽤户ID", user.getId());
}
/*
@PostMapping(value = "/addUser")
public User addUser(User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile) throws IOException
*/
@Test
public void testAddUser() {
String url = urlPrefix + "/addUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("name", "赵晓丽");
formData.add("password", "123456");
formData.add("sex", "true");
formData.add("birthDay", "2018-01-26");
formData.add("photo", "user.png");
formData.add("email", "[email protected]");
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
User user = restTemplate.postForObject(url, formData, User.class);
assertNotNull("⽤户ID", user.getId());
}
/*
@PutMapping(value = "/updateUser")
public void updateUser(User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile) throws IOException
*/
@Test
public void testUpdateUser() {
String url = urlPrefix + "/updateUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>
();
formData.add("id", "6");
formData.add("name", "赵晓丽");
formData.add("password", "123456");
formData.add("sex", "true");
formData.add("birthDay", "2018-01-27");
formData.add("photo", "user1.png");
formData.add("email", "[email protected]");
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
restTemplate.put(url, formData);
}
/*
@DeleteMapping(value = "/deleteUserByIds")
public void delteUserByIds(@RequestParam(value = "ids") Integer[] ids)
*/
@Test
public void testDeleteUser() {
String url = urlPrefix + "/deleteUserByIds?ids={id}";
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("id", "4,5,6");
restTemplate.delete(url, parameters);
}
/*@GetMapping(value = "/queryUserByPage")
public List<User> queryUserByPage(@RequestParam(value = "page",defaultValue = "1")
Integer pageNow,
@RequestParam(value = "rows",defaultValue =
"10") Integer pageSize,
@RequestParam(value = "column",required = false)
String column,
@RequestParam(value = "value",required = false)
String value)
*/
@Test
public void testQueryUserByPage() {
String url = urlPrefix + "/queryUserByPage?page={page}&rows={rows}&column= { column }&value = {value} ";
Map<String, Object> params = new HashMap<String, Object>();
params.put("page", 1);
params.put("rows", 10);
params.put("column", "name");
params.put("value", "⼩");
User[] users = restTemplate.getForObject(url, User[].class, params);
assertNotNull("⽤户数据", users);
}
/*
@GetMapping(value = "/queryUserCount")
public Integer queryUserCount(@RequestParam(value = "column",required = false)
String column,
@RequestParam(value = "value",required = false)
String value)
*/
@Test
public void testQueryUserCount() {
String url = urlPrefix + "/queryUserCount?column={column}&value={value}";
//模拟表单数据
Map<String, Object> parameters = new HashMap<>();
parameters.put("column", "name");
parameters.put("value", "晓");
Integer count = restTemplate.getForObject(url, Integer.class, parameters);
assertNotNull(count);
}
/*
@GetMapping(value = "/queryUserById")
public User queryUserById(@RequestParam(value = "id") Integer id)
*/
@Test
public void testQueryUserById() {
String url = urlPrefix + "/queryUserById?id={id}";
//模拟表单数据
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", "2");
User user = restTemplate.getForObject(url, User.class, parameters);
assertNotNull("⽤户ID", user.getId());
}
}
- RestUserControllerTests
/**
* RestUserController测试类
*/
@SpringBootTest(classes = {Application.class})
@RunWith(SpringRunner.class)
public class RestUserControllerTests {
@Resource
private RestTemplate restTemplate;
private String urlPrefix = "http://127.0.0.1:8888/restUserManager";
/*
@PostMapping(value = "/registerUser")
public User registerUser(@RequestPart(value = "user") User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile) throws IOException {
*/
@Test
public void testRegisterUser() {
String url = urlPrefix + "/registerUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>
();
User user = new User(null, "张晓磊", true, "123456", new Date(), "aa.png", "[email protected]");
formData.add("user", user);
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
User registerUser = restTemplate.postForObject(url, formData, User.class);
assertNotEquals("⽤户ID", registerUser.getId());
}
/*
@PostMapping(value = "/userLogin")
public User userLogin(@RequestBody User user)
*/
@Test
public void testUserLogin() {
String url = urlPrefix + "/userLogin";
//模拟表单数据
User user = new User();
user.setName("张晓磊");
user.setPassword("123456");
User loginUser = restTemplate.postForObject(url, user, User.class);
assertNotEquals("⽤户ID", loginUser.getId());
}
/*
@PostMapping(value = "/addUser")
public User addUser(@RequestPart(value = "user") User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile) throws IOException
*/
@Test
public void testAddUser() {
String url = urlPrefix + "/addUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>
();
User user = new User(null, "温晓琪", true, "123456", new Date(), "aa.png", "[email protected]");
formData.add("user", user);
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
User dbUser = restTemplate.postForObject(url, formData, User.class);
assertNotNull("⽤户ID", dbUser.getId());
}
/*
@PutMapping(value = "/updateUser")
public void updateUser(@RequestPart(value = "user") User user,
@RequestParam(value = "multipartFile",required = false)
MultipartFile multipartFile) throws IOException {
*/
@Test
public void testUpdateUser() {
String url = urlPrefix + "/updateUser";
//模拟表单数据
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>
();
User user = new User(20, "温晓琪", false, "123456", new
Date(), "aa.png", "[email protected]");
user.setId(9);
formData.add("user", user);
//模拟⽂件上传
FileSystemResource fileSystemResource = new
FileSystemResource("/Users/admin/Desktop/head.png");
formData.add("multipartFile", fileSystemResource);
restTemplate.put(url, formData);
}
/*
@DeleteMapping(value = "/deleteUserByIds")
public void delteUserByIds(@RequestParam(value = "ids") Integer[] ids)
*/
@Test
public void testDeleteUser() {
String url = urlPrefix + "/deleteUserByIds?ids={id}";
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("id", "4,5,6");
restTemplate.delete(url, parameters);
}
/*
@GetMapping(value = "/queryUserByPage")
public List<User> queryUserByPage(@RequestParam(value = "page",defaultValue = "1")
Integer pageNow,
@RequestParam(value = "rows",defaultValue =
"10") Integer pageSize,
@RequestParam(value = "column",required = false)
String column,
@RequestParam(value = "value",required = false)
String value)
*/
@Test
public void testQueryUserByPage() {
String url = urlPrefix + "/queryUserByPage?page={page}&rows={rows}&column= { column }&value = {value} ";
Map<String, Object> params = new HashMap<String, Object>();
params.put("page", 1);
params.put("rows", 10);
params.put("column", "name");
params.put("value", "⼩");
User[] users = restTemplate.getForObject(url, User[].class, params);
assertNotNull("⽤户数据", users);
}
/*
@GetMapping(value = "/queryUserCount")
public Integer queryUserCount(@RequestParam(value = "column",required = false)
String column,
@RequestParam(value = "value",required = false)
String value)
*/
@Test
public void testQueryUserCount() {
String url = urlPrefix + "/queryUserCount?column={column}&value={value}";
//模拟表单数据
Map<String, Object> parameters = new HashMap<>();
parameters.put("column", "name");
parameters.put("value", "晓");
Integer count = restTemplate.getForObject(url, Integer.class, parameters);
assertNotNull(count);
}
/*
@GetMapping(value = "/queryUserById")
public User queryUserById(@RequestParam(value = "id") Integer id)
*/
@Test
public void testQueryUserById() {
String url = urlPrefix + "/queryUserById?id={id}";
//模拟表单数据
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", "2");
User user = restTemplate.getForObject(url, User.class, parameters);
assertNotNull("⽤户ID", user.getId());
}
}
- Application
/**
* SpringBoot入口类
*/
@SpringBootApplication
@MapperScan(basePackages = "com.baizhi.dao")
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
@Bean
public RedisTemplate redisTemplate() {
return new RedisTemplate();
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
集成Redis实现⼆级缓存
- 环境准备
虚拟机已安装Redis,并正常运行 - ApplicationContextHolder
/**
* 该接口为标记接口、Spring工厂在初始化的时候会自动注入applicationContext
*/
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
- UserDefineRedisCache
/**
* 集成Redis开启Mybatis二级缓存
*/
public class UserDefineRedisCache implements Cache {
private static final Logger LOGGER = LoggerFactory.getLogger(UserDefineRedisCache.class);
//记录的是Mapper的namespace
private String id;
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextHolder.getBean("redisTemplate");
public UserDefineRedisCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
LOGGER.debug("将查询结果缓存到Redis");
ValueOperations operations = redisTemplate.opsForValue();
operations.set(key, value, 30, TimeUnit.MINUTES);
}
@Override
public Object getObject(Object key) {
LOGGER.debug("获取缓存结果");
ValueOperations opsForValue = redisTemplate.opsForValue();
return opsForValue.get(key);
}
@Override
public Object removeObject(Object key) {
LOGGER.debug("删除Redis中的key:" + key);
ValueOperations opsForValue = redisTemplate.opsForValue();
Object value = opsForValue.get(key);
redisTemplate.delete(key);
return value;
}
@Override
public void clear() {
LOGGER.debug("删除所有Redis中的缓存");
redisTemplate.execute((RedisCallback) connection -> {
connection.flushDb();
return null;
});
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
}
实现Mysql的读写分离
背景
⼀个项⽬中数据库最基础同时也是最主流的是单机数据库,读写都在⼀个库中。当⽤户逐渐增多,单机数据库⽆法满⾜性能要求时,就会进⾏读写分离改造(适⽤于读多写少),写操作⼀个库,读操作多个库,通常会做⼀个数据库集群,开启主从备份,⼀主多从,以提⾼读取性能。当⽤户更多读写分离也⽆法满⾜时,就需要分布式数据库了-NoSQL。 正常情况下读写分离的实现,⾸先要做⼀个⼀主多从的数据库集群,同时还需要进⾏数据同步。
数据库主从搭建
Master配置
- 修改/etc/my.cnf
[root@CentOS ~]# vim /etc/my.cnf
[mysqld]
server-id=1
log-bin=mysql-bin
log-slave-updates
slave-skip-errors=all
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
- 重启MySQL服务
[root@CentOS ~]# systemctl restart mysqld
- 登录MySQL主机查看状态
[root@CentOS ~]# mysql -uroot -proot
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.6.42-log MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show master status\G;
*************************** 1. row ***************************
File: mysql-bin.000006
Position: 120
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
ERROR:
No query specified
Slave 配置
- 修改/etc/my.cnf⽂件
[root@Mysql2 ~]# vim /etc/my.cnf
[mysqld]
server-id=2
log-bin=mysql-bin
log-slave-updates
slave-skip-errors=all
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
- 重启MySQL服务
systemctl restart mysqld
- MySQL配置从机