这两天主要是把项目的进度往前推了一点,完成了一些小项目点的实现。
目录
雪花算法
public class Main {
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
// -1L 二进制就是1111 1111 为什么?
// -1 左移12位就是 1111 1111 0000 0000 0000 0000
// 异或 相同为0 ,不同为1
// 1111 1111 0000 0000 0000 0000
// ^
// 1111 1111 1111 1111 1111 1111
// 0000 0000 1111 1111 1111 1111 换算成10进制就是4095
private long sequenceMask = -1L ^ (-1L << sequenceBits);
//记录产生时间毫秒数,判断是否是同1毫秒
private long lastTimestamp = -1L;
public long getWorkerId(){
return workerId;
}
public long getDatacenterId() {
return datacenterId;
}
public long getTimestamp() {
return System.currentTimeMillis();
}
public Main() {
}
public Main(long workerId, long datacenterId, long sequence) {
// 检查机房id和机器id是否超过31 不能小于0
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
this.sequence = sequence;
}
// 这个是核心方法,通过调用nextId()方法,
// 让当前这台机器上的snowflake算法程序生成一个全局唯一的id
public synchronized long nextId() {
// 这儿就是获取当前时间戳,单位是毫秒
long timestamp = timeGen();
// 判断是否小于上次时间戳,如果小于的话,就抛出异常
if (timestamp < lastTimestamp) {
System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
// 下面是说假设在同一个毫秒内,又发送了一个请求生成一个id
// 这个时候就得把seqence序号给递增1,最多就是4096
if (timestamp == lastTimestamp) {
// 这个意思是说一个毫秒内最多只能有4096个数字,无论你传递多少进来,
//这个位运算保证始终就是在4096这个范围内,避免你自己传递个sequence超过了4096这个范围
sequence = (sequence + 1) & sequenceMask;
//当某一毫秒的时间,产生的id数 超过4095,系统会进入等待,直到下一毫秒,系统继续产生ID
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
// 这儿记录一下最近一次生成id的时间戳,单位是毫秒
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) | sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
//获取当前时间戳
private long timeGen(){
return System.currentTimeMillis();
}
/**
* main 测试类
*
* @param args
* @return
*/
public static void main(String[] args) {
Main snowFlow = new Main(1, 1, 1);
System.out.println(snowFlow.nextId());
}
}
分析:
雪花算法是使用分布式环境下的唯一ID生成算法,在分布式高并发的环境下,要保证ID的唯一性和生成的优先度,雪花算法就是为了实现这个功能。
它用long类型接收获得的唯一的ID。但是在我得数据库中id是vachar类型,所以我在接收的时候换了一下类型,就像这样:
雪花算法的目的是在分布式系统中产生全局唯一且趋势递增的。
正则表达式
//QQ邮箱的验证
Pattern p1=Pattern.compile("^([A-Za-z0-9_\\-\\.])+\\@([A-Za-z0-9_\\-\\.])+\\.([A-Za-z]{2,4})$");
Matcher m1=p1.matcher(email);
if(m1.find()) {
}
else {
Alert alert=new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("警告");
alert.setHeaderText(null);
alert.setContentText("QQ邮箱格式不对!");
alert.showAndWait();
return;
}
//设置的密码的格式的验证
Pattern p=Pattern.compile("^(?=.*\\d)(?=.*[a-zA-Z])(?=.*[^\\da-zA-Z\\s]).{8,16}$");
Matcher m=p.matcher(password);
if(m.find()){
}
else { Alert alert=new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("警告");
alert.setHeaderText(null);
alert.setContentText("密码强度不够,必须是8-16位,需要有字母,数字,和特殊字符");
alert.showAndWait();
return;
}
分析:这里一开始的时候也是一直错,我明明格式什么的都写对了的,但是就是实现不了我想实现的功能,这就是一个非常非常大的坑,新手非常容易载。用字符串.matches匹配的正则表达式,相当于会在正则表达式前后加上^ $,是匹配整个大字符串是否满足正则表达式,而不会匹配到其中满足条件的子串, 所以这里其实是有坑的,不能直接用matches比较,所以我用了三步完成了正则表达式的判断。
Mysql
inner join
示例如下:
select
qpd.device_id,
qpd.question_id,
qpd.result
from
question_practice_detail as qpd
inner join user_profile as up on up.device_id = qpd.device_id
and up.university = '浙江大学'
order by
question_id;
查看所有来自浙江大学的用户题目回答明细情况。
left join
示例如下:
select
university,
difficult_level,
round(
count(qpd.question_id) / count(distinct qpd.device_id),
4
) as avg_answer_cnt
from
question_practice_detail as qpd
left join user_profile as up on up.device_id = qpd.device_id
left join question_detail as qd on qd.question_id = qpd.question_id
group by
university,
difficult_level;
计算一些参加了答题的不同学校、不同难度的用户平均答题量。