1349 – View’s SELECT contains a subquery in the FROM clause

场景:要导出视图并在另外一台服务器上创建,结果创建失败了。错误如标题所示,经过搜索找到原因,现总结下。

MySQL文档中对版本做了说明,5.7.7以前的版本不支持子查询的视图语句,要实现可以通过把子查询语句拆成单个视图,最后拼接在一起;获取使用高版本的MySQL(安装版本>5.7.7)即可。

补充:使用Navicat导出视图语句的方法 继续阅读1349 – View’s SELECT contains a subquery in the FROM clause

安全代码的检查清单

 

安全代码的检查清单

安全管理

有没有安全更新的策略和落实计划?

有没有安全漏洞的保密共识和规范?

有没有安全缺陷的评估和管理办法?

软件是不是使用最新的安全修复版?

有没有定义、归类和保护敏感信息?

有没有部署多层次的安全防御体系?

安全防御能不能运转良好、及时反应?

不同的安全防御机制能不能独立运转?

系统管理、运营人员的授权是否恰当?

有没有风险管理的预案和长短期措施?

代码评审

数值运算会不会溢出?

有没有检查数值的合理范围 继续阅读安全代码的检查清单

监听Apollo配置变动

监听Apollo配置变动


import lombok.extern.slf4j.Slf4j;
import com.ctrip.framework.apollo.ConfigFile;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import org.springframework.stereotype.Component;
/**
* 监听Apollo配置属性变化事件
* 注意:Apollo配置的namespace为application,属性为json.config.{xx},属性值是JSON字符串
*/
@Slf4j
@Component
public class ApolloRefreshListener {

   /**
    * json.config.value=[{"someString":"hello","someInt":100}]
    */
   @ApolloJsonValue("${json.config.value}")
   private List<JsonBean> jsonBeanList;

   /**
    * 监听namespace,默认application,多个("namespace1","namespace2")
    */
   @ApolloConfigChangeListener("application")
   private void someOnChange(ConfigChangeEvent changeEvent) {
       boolean hasChange = false;
       //update injected value of batch if it is changed in Apollo
       for (String changedKey : changeEvent.changedKeys()) {
           log.info("changedKey:{}", changedKey);
           //json.config的key发生了改变(json.config.xx的配置发生了改变)
           if (changedKey.startsWith("json.config.")) {
               hasChange = true;
               break;
          }
      }
       if (hasChange) {
           ConfigFile content = ConfigService.getConfigFile(changeEvent.getNamespace(), ConfigFileFormat.Properties);
           List<JsonBean> result = jsonBeanList;
           log.info("result:{}", result);
      }
  }
   
   
}

直接获取json配置的namespace(添加namespace时,选择private,名称后缀选择json格式),代码如下 继续阅读监听Apollo配置变动

读MySQL数据库数据字段时间多了8小时

背景:使用Java程序的java.util.Date类型读取出MySQL中的Timestamp的值时发现大了8小时。

百度了下设置MySQL的时区,如下:

set global time_zone = '+8:00';##修改mysql全局时区为北京时间,即我们所在的东8区
set time_zone = '+8:00';##修改当前会话时区
flush privileges; #立即生效
show variables like "%time_zone%";

但是未能解决。又继续查看代码中的数据库连接。发现一处地方可能是问题的原因。

多了8小时的连接设置:?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC

注意到可能是这个serverTimezone的问题,将其修改为serverTimezone=Asia/Shanghai ,再试一下,擦搞定了。赶紧记下来,于是有了这篇笔记。

多线程处理任务后,继续主线程任务

业务场景:获取三个表数据,发送至三个接口,响应后删除表数据

1 读取三张表数据


/**
 * 获取所有表数据
 */
private void getAllTableData(String curentTime, JSONArray requestArray) {
       List<DeviceStatus> deviceStatusList = getDeviceStatusLists(curentTime);
        int deviceStatusListSize = 0;
        if (!CollectionUtils.isEmpty(deviceStatusList)) {
            JSONObject json = new JSONObject();
            json.put("url", deviceStatusUrl);
            JSONObject param = new JSONObject();
            param.put("list", deviceStatusList);
            json.put("data", param);
            requestArray.add(json);
            deviceStatusListSize = deviceStatusList.size();
        }
        logger.info("deviceBriefStatusList-size:{}", deviceBriefStatusListSize);
        //***另外两张表
 }

2 将数据发送到线程里

public void executeScheduleTask() {
	String curentTime = DateUtils.getNowText();
	logger.info("操作时间:{}", curentTime);
   /*
    数据和请求地址放入到requestArray中
   */
    JSONArray requestArray = new JSONArray();
    getAllTableData(curentTime, requestArray);

    if (!CollectionUtils.isEmpty(requestArray)) {
        //申明线程池
        ExecutorService exc = Executors.newFixedThreadPool(requestArray.size());
        //申明数据毁掉处理类List<Future<JSONObject>>
        List<Future<JSONObject>> futures = new ArrayList<>();
        for (int i = 0; i < requestArray.size(); i++) {
            JSONObject json = requestArray.getJSONObject(i);
            //申请单个线程执行类
            DataHandleRequest call = new DataHandleRequest(json);
            //提交单个线程
            Future<JSONObject> future = exc.submit(call);
            //将每个线程放入线程集合,这里如果任何一个线程的执行结果没有毁掉,线程后都会自动堵塞
            futures.add(future);
        }
        //所有线程执行完毕之后会执行下面的循环,然后通过循环每个线程后执行线程的get()方法,每个线程的执行结果

        List<String> succList = new ArrayList<>();
        try {
            for (Future<JSONObject> future : futures) {
                JSONObject json = future.get();
                String returnData = json.getString("returnData");
                JSONObject valueJson = JSONObject.parseObject(returnData);
                if (valueJson.containsKey("code") && "000000".equals(valueJson.getString("code"))) {
                    succList.add(valueJson.getString("data"));
                }
                logger.info("同步调用结果:{}", returnData);
            }
            exc.shutdown();
        } catch (Exception e) {
            logger.error("同步数据失败:{}", e);
        }
        //删除已同步数据表
        deleteTable(curentTime, succList);
    }

  
    logger.info("同步数据表结束,耗时:cost={}ms", cost);
}

3数据发送,创建一个执行线程任务类DataHandleRequest 继续阅读多线程处理任务后,继续主线程任务

1267 – Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation

MySQL在做表关联查询,报错,信息如下

1267 - Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '='

报错原因:字段间的编码格式不一致;

1查看表字符编码,会显示建表的字符编码

sql>show create table t_user_device_relation;

2 设置字段编码,如设置为utf8_general_ci

sql>ALTER TABLE t_user_device_relation MODIFY COLUMN id VARCHAR(32) CHARACTER SET utf8_general_ci COLLATE utf8_unicode_ci;

备注:设置没有用,使用navicat直接修改,也没成功;就直接重新建表,导入数据,OK!

MySQL编写触发器

触发器语法示例:

CREATE TRIGGER trigger_name trigger_time trigger_event ON tb_name FOR EACH ROW trigger_stmt
trigger_name:触发器的名称
tirgger_time:触发时机,为BEFORE或者AFTER
trigger_event:触发事件,为INSERT、DELETE或者UPDATE
tb_name:表示建立触发器的表明,就是在哪张表上建立触发器
trigger_stmt:触发器的程序体,可以是一条SQL语句或者是用BEGIN和END包含的多条语句
所以可以说MySQL创建以下六种触发器:
BEFORE INSERT,BEFORE DELETE,BEFORE UPDATE
AFTER INSERT,AFTER DELETE,AFTER UPDATE

创建多个执行语句的触发器:

CREATE TRIGGER 触发器名 BEFORE|AFTER 触发事件
ON 表名 FOR EACH ROW
BEGIN
    执行语句列表(用分号隔开)
END

如表:t_device_status_info

1 创建触发器

CREATE TRIGGER t_device_status_info_update 
AFTER UPDATE on t_device_status_info FOR EACH ROW
BEGIN
	insert into t_device_status_info_tmp_modify
		(id, device_id, `name`, `value`, state,
		create_time, update_time)
	values 
		(new.id, new.device_id, new.name, new.value, new.state,
		new.create_time, new.update_time);
END;

补充插入或更新

replace into t_device_status_info_tmp_modify
(id, device_id, `name`, `value`, state,
create_time, update_time)
values
(new.id, new.device_id, new.name, new.value, new.state,
new.create_time, new.update_time);

2 创建一个删除表操作的触发器

CREATE TRIGGER t_device_status_info_del 
BEFORE DELETE on t_device_status_info FOR EACH ROW
BEGIN
	insert into t_device_status_info_tmp_del
		(id, device_id, name, value, state,
		create_time, update_time)
	values 
		(old.id, old.device_id, old.name, old.value, old.state,
		old.create_time, old.update_time);
END;

3 查看触发器 继续阅读MySQL编写触发器

Springboot配置注入静态属性

1 application.properties配置文件:

http.config.connectTimeout=300000
http.config.readTimeout=300000

 

2 使用静态set方法注入:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component(value = "HttpConfig")
@ConfigurationProperties("http.config")
public class HttpConfig {

    public static int readTimeout;

    public static int connectTimeout;

    @Value("${http.config.readTimeout}")
    public static void setReadTimeout(int readTimeout) {
        HttpConfig.readTimeout = readTimeout;
    }

    @Value("${http.config.connectTimeout}")
    public static void setConnectTimeout(int connectTimeout) {
        HttpConfig.connectTimeout = connectTimeout;
    }

    public static int getReadTimeout() {
        return readTimeout;
    }

    public static int getConnectTimeout() {
        return connectTimeout;
    }
}

 

3 静态类调用 继续阅读Springboot配置注入静态属性

SpringBoot发送一个Form数据的post请求

通过post发送一个Form格式的数据请求,示例代码如下:

METHOD:POST
Content-Type:application/x-www-form-urlencoded

private String sendPostFormRequest(MultiValueMap<String, String> params) {
        RestTemplate client = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        HttpMethod method = HttpMethod.POST;
        //表单方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //将请求头部和参数合成一个请求
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
        ResponseEntity<String> response = client.exchange(tokenUrl, method, requestEntity, String.class);
        return response.getBody();
    }

导入的包import org.springframework.*;

调用sendPostFormRequest继续阅读SpringBoot发送一个Form数据的post请求