JavaDaily
- 2019-07-22 Integer的缓存机制
- 2019-07-22 fail-fast和fail-safe
- 2019-07-23 消息队列的应用场景
- 2019-07-23 Elasticsearch学习
- 2019-08-01 Java并发编程
- 2019-08-06 SELECT … FOR UPDATE
- 2019-08-24 BigDecimal的使用
- 2019-09-05 Java NIO
- 2019-10-14 Stream和Array转换
- 2019-10-14 查找元素在数组中的索引
- 2019-10-15 计算元素在集合中出现的次数
- 2019-10-17 将Set转为array
- 2019-10-21 在List中找到某元素
- 2019-10-22 isEmpty()和isBlank()的区别
- 2019-11-16 算法技巧积累
- 2019-11-22 算法常见模式
- 2019-11-26 动态规划套路总结
- 2019-11-30 设计模式一个很好的讲解专栏
- 2019-12-01 UML图总结
- 2019-12-13 Linux在线学习资料
- 2019-12-15 Bloom Filter 布隆过滤器
- 2019-12-17 前端YARN使用
- 2019-12-19 Vue项目解决跨域问题
- 2019-12-19 在服务器部署ES无法访问9200端口的问题
- 2019-12-22 Java对象转换,深拷贝
- 2019-12-25 将List<Map<String, String>> 合并为Map<String, String>
- 2019-12-25 Lombok @Builder与@NoArgsConstructor注解冲突
- 2019-12-26 SpringBoot通用service、dao模板
- 2019-12-30 Cookie、Session、Token、JWT的区别
- 2020-01-05 Java 8 Stream 的终极技巧——Collectors 操作
- 2020-01-06 Java Collection 移除元素的几种方式
- 2020-01-07 异常处理
- 2020-01-07 mock测试你的web应用
- 2020-01-07 SpringSecurity 相关
- 2020-01-08 日志体系
- 2020-01-14 MySQL时间类型存储
- 2020-01-15 大数据方面
- 2020-01-15 Docker Load 命令的一个注意点
- 2020-01-15 阅读的一些博客
- 2020-01-15 ElasticSearch
- 2020-01-22 阅读的一些文章
- 2020-02-24 数据库 事务 锁 隔离级别等
- 2020-02-26 Java8 方法区 永久代 元空间
- 2020-02-26 Java类卸载
- 2020-02-26 Java动态代理 反射
- 2020-02-26 Java中的锁,MySQL中的锁
- 2020-02-27 Java8 JVM CodeCache
- 2020-03-07 优化if/else
- 2020-03-10 Java中Wait、Sleep和Yield方法的区别
- 2020-03-22 MySQL中varchar存储汉字
2019-07-22 Integer的缓存机制
猜想以下代码输出?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class IntegerCache {
public static void main(String[] args) {
Integer integer1 = 3;
Integer integer2 = 3;
if (integer1 == integer2){
System.out.println("integer1 == integer2");
}
else{
System.out.println("integer1 != integer2");
}
Integer integer3 = 300;
Integer integer4 = 300;
if (integer3 == integer4){
System.out.println("integer3 == integer4");
}
else{
System.out.println("integer3 != integer4");
}
}
}
看代码的时候,出于惯例,一开始我认为这里“==”比较的是对象的地址,因此我认为两个比较应该输出都是不等的。因为在Java中,==比较的是对象应用,而equals比较的是值。这里虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以认为两个if判断都是false的。
可是程序的结果是:1
2integer1 == integer2
integer3 != integer4
原因是:
在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。
- 适用于整数值区间-128 至 +127。
- 只适用于自动装箱。使用构造函数创建对象不适用。
Java的编译器把基本数据类型自动转换成封装类对象的过程叫做自动装箱,相当于使用valueOf方法:1
2Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood
JDK中Integer的valueOf()源码如下,IntegerCache是Integer类中定义的一个private static的内部类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
源码表示,在创建对象之前先从IntegerCache.cache中寻找。如果没找到才使用new新建对象。
阅读:
[1]Integer的缓存机制
2019-07-22 fail-fast和fail-safe
- 快速失败(fail-fast):一旦系统发现异常,立刻抛出异常,而不是试图继续可能存在缺陷的过程
- 安全失败(fail-save):Java中提供的一些采用了fail-safe机制的集合类。这样的集合容器在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
fail-fast 机制是 Java 集合 (Collection) 中的一种是一种错误检测机制,JDK 并不保证 fail-fast 机制一定会发生。如果在迭代器迭代的过程中会检查对集合的结构进行任何的修改,每次获得下一个元素时,如果发现有任何修改,会立刻抛出异常 ConcurrentModificationException,而不是等遍历完了再抛出异常。所有迭代器的实现都是快速失败的设计。
Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。
阅读:
[1]谈谈fail-fast与fail-safe
[2]fail-fast和fail-safe
2019-07-23 消息队列的应用场景
- 异步处理
- 用户注册,将注册信息写入数据库后,直接返回成功。然后将消息写入消息队列,邮件服务和短信服务从队列中取出消息,然后分别发送邮件、短信。因为这里的注册过程中,邮件和短信不是必须的,只是起到通知用户的作用。
- 应用解耦
- 双11用户下单后,订单系统需要通知库存系统扣减库存,传统做法是订单系统调用库存系统的接口。这样订单服务和库存服务耦合度较高,且若库存系统服务失败,则下单也可能会失败。因此引入消息队列,当用户下单后,订单系统完成持久化处理,随后将消息写入消息队列,返回用户订单下单成功。库存系统需要订阅下单的消息,获取下单消息,进行库存操作。即使库存系统出现故障,消息队列也能保证消息的可靠投递,不会导致消息丢失。
- 流量削峰
- 秒杀活动,一般会因为流量过大,导致应用服务挂掉。为了解决这个问题,一般在应用前端加入消息队列。这样可以控制活动人数,超过设定的阀值的订单直接丢弃,可以缓解短时间的高流量压垮应用(应用程序按自己的最大处理能力获取订单)。服务器收到用户的请求之后,首先写入消息队列,若消息队列长度超过最大值,则直接抛弃用户请求或跳转到错误页面。秒杀业务获取消息队列中的请求信息,再做后续处理。
阅读:
[1]《RabbitMQ的应用场景以及基本原理介绍》
[2]消息队列-推/拉模式学习 & ActiveMQ及JMS学习
[3]Github 消息队列
2019-07-23 Elasticsearch学习
阅读:
[1]Elasticsearch学习,请先看这一篇!
2019-08-01 Java并发编程
阅读:
[1]Java多线程中static变量的使用
[2]Java并发编程笔记——J.U.C之executors框架:executors框架设计理念
[3]Java并发编程笔记——J.U.C之executors框架:ThreadPoolExecutor
[4]Java多线程之Executor框架<Callable、Future、Executor和ExecutorService>Java中类不可以多继承,但是接口可以多继承。
如RunnableFuture接口:1
2
3
4
5
6
7
8
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
2019-08-06 SELECT … FOR UPDATE
SELECT … FROM t_some_table WHERE … FOR UPDATE,该语句的作用就是一个行级锁(对游标里所有的记录),如果其他进程要更新这个游标行级锁里的记录,就必须等待当前进程的COMMIT或者回滚。该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止。
SELECT FOR UPDATE是行级锁,也是悲观锁、排他锁,为了防止并发修改,在处理某批数据的时候,使用该语句,对每行数据增加行级锁,属于悲观锁。commit 或 rollback 释放锁定。
注意:
- 要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
- SELECT FOR UPDATE 仅适用于InnoDB,且必须在事务区块(BEGIN/COMMIT)中才能生效。在进行事务操作时,通过“FOR UPDATE”语句,MySQL会对查询结果集中每行数据都添加排他锁,其他线程对该记录的更新与删除操作都会阻塞。排他锁包含行锁、表锁。
- 由于InnoDB预设是Row-Level Lock,所以只有“明确”地指定主键,MySQL才会执行Row lock (只锁住被选取的数据) ,否则MySQL将会执行Table Lock (将整个数据表单给锁住)。
使用场景:保证数据一致性。
如:假设有A、B两个用户同时各购买一件 id=1 的商品,用户A获取到的库存量为 1000,用户B获取到的库存量也为 1000,用户A完成购买后修改该商品的库存量为 999,用户B完成购买后修改该商品的库存量为 999,此时库存量数据产生了不一致。
两种解决方案:
悲观锁解决方案:
每次获取商品时,对该商品加排他锁。也就是在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录。悲观锁适合写入频繁的场景。乐观锁解决方案:
每次获取商品时,不对该商品加锁。在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新,反之程序重新获取库存量,再次进行比较,直到两个库存量的数值相等才进行数据更新。乐观锁适合读取频繁的场景。
例:假设有个表t_product,里面有id跟name两列,id是主键。
1 | // 例1: (明确指定主键,并且有此数据,row lock) |
Mybatis使用:1
2
3
4
5
6
7// 定义接口:
ProductPo getProductLock(@Param("productId") int productId);
// mybatis xml中实现
<select id="getProductLock" parameterType="Integer" resultMap="BaseResultMap">
SELECT * FROM t_product WHERE id = #{productId} FOR UPDATE
</select>
阅读:
[1]mysql SELECT FOR UPDATE语句使用示例
[2]SELECT语句中的for update的用法(锁的运用)
[3]数据库:Mysql中“select … for update”排他锁分析
[4]when-to-use-select-for-update
[5]并发控制机制
[6]Select For update语句浅析
2019-08-24 BigDecimal的使用
在初始化BigDecimal对象的时候,建议使用new BigDecimal(String)或者BigDecimal.valueOf()方法,这样可以准确精度。1
2
3
4
5
6
7
8
9public static void main(String[] args)
{
BigDecimal a = new BigDecimal("19.9977");
BigDecimal b = new BigDecimal(19.9977D);
BigDecimal c = BigDecimal.valueOf(19.9977D);
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
输出结果是:1
2
319.9977
19.997699999999998254907040973193943500518798828125
19.9977
关于四舍五入:1
2
3
4
5
6
7public static void main(String[] args)
{
BigDecimal a = new BigDecimal("19.9977");
BigDecimal b = BigDecimal.valueOf(2D);
BigDecimal result = a.multiply(b).setScale(2, RoundingMode.HALF_UP);
System.out.println(result); // 40.00
}
通过RoundingMode来进行四舍五入,RoundingMode有八种舍入模式:
- RoundingMode.UP:舍入远离零的舍入模式。在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。注意,此舍入模式始终不会减少计算值的大小。
- RoundingMode.DOWN:接近零的舍入模式。在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。注意,此舍入模式始终不会增加计算值的大小。
- RoundingMode.CEILING:接近正无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUNDUP 相同;如果为负,则舍入行为与 ROUNDDOWN 相同。注意,此舍入模式始终不会减少计算值。
- RoundingMode.FLOOR:接近负无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUNDDOWN 相同;如果为负,则舍入行为与 ROUNDUP 相同。注意,此舍入模式始终不会增加计算值。
- RoundingMode.HALFUP:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 ROUNDUP 相同;否则舍入行为与 ROUND_DOWN 相同。注意,这是我们在小学时学过的舍入模式(四舍五入)。
- RoundingMode.HALFDOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与 ROUNDUP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。
- RoundingMode.HALFEVEN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUNDHALFUP 相同;如果为偶数,则舍入行为与 ROUNDHALF_DOWN 相同。注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。如果前一位为奇数,则入位,否则舍去。以下例子为保留小数点1位,那么这种舍入方式下的结果。1.15 ==> 1.2 ,1.25 ==> 1.2
- RoundingMode.UNNECESSARY:断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
参考阅读:
[1]如何使用BigDecimal?
2019-09-05 Java NIO
读写文件:
阅读 Java NIO File Read Write with Channels
2019-10-14 Stream和Array转换
[1]Java 8 – Convert stream to array
[2]Java – How to convert Array to Stream
2019-10-14 查找元素在数组中的索引
[1]Find the index of an element in an array in Java
2019-10-15 计算元素在集合中出现的次数
[1]Frequency of object in collection
2019-10-17 将Set转为array
[1]Set to Array in Java
[2]Java Error: Generic array creation
2019-10-21 在List中找到某元素
[1]How to Find an Element in a List with Java
2019-10-22 isEmpty()和isBlank()的区别
org.apache.commons.lang.StringUtils 类提供了String的常用操作,最为常用的判空有如下两种:isEmpty(CharSequence cs) 和 isBlank(CharSequence cs)。
源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public static boolean isEmpty(CharSequence cs) {
return cs == null || cs.length() == 0;
}
public static boolean isNotEmpty(CharSequence cs) {
return !isEmpty(cs);
}
public static boolean isBlank(CharSequence cs) {
int strLen;
if (cs != null && (strLen = cs.length()) != 0) {
for(int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
} else {
return true;
}
}
public static boolean isNotBlank(CharSequence cs) {
return !isBlank(cs);
}
总结:
- StringUtils.isEmpty(String str)判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0
- StringUtils.isBlank(String str)判断某字符串是否为空或长度为 0 或由空白符 (whitespace) 构成
- StringUtils.isNotEmpty(String str)等价于!isEmpty(String str)
- StringUtils.isNotBlan(String str)等价于!isBlank(String str)
建议:
用StringUtils.isBlank(CharSequence cs) 来执行判空操作,判断的条件更多更具体,特别是进行参数校验时,推荐使用。
2019-11-16 算法技巧积累
[1]位运算相关操作
[2]一些常用的算法技巧总结
[3]算法数据结构中有哪些奇技淫巧?
2019-11-22 算法常见模式
2019-11-26 动态规划套路总结
[1]告别动态规划,连刷40道动规算法题,我总结了动规的套路
[2]动态规划该如何优化?我总结了这些套路,以后优化就是分分钟
[3]动态规划详解
[4]【算法】动态规划问题集锦与讲解
2019-11-30 设计模式一个很好的讲解专栏
[1]史上最全设计模式导学目录(完整版)
[2][置顶] 刘伟《设计模式》一书PPT浏览及下载地址
2019-12-01 UML图总结
[1]UML各种图总结-精华
2019-12-13 Linux在线学习资料
[1]《Linux就该这么学》
2019-12-15 Bloom Filter 布隆过滤器
- Bloom Filter一种来检索元素是否在给定大集合中的数据结构,这种数据结构是高效且性能很好的,但缺点是具有一定的错误识别率和删除难度。并且,理论情况下,添加到集合中的元素越多,误报的可能性就越大。
- 占用内存空间少,它支持insert和contains,两者均在常数时间内运行
- Bloom有可能会误报,即:
- 当contains(x)返回true, 那么x有很大的可能在集合中,也有很小的一部分概率不在
- 当contains(x)返回false, 那么x一定不在集合中
- 应用场景:
- 判断给定数据是否存在:比如判断一个数字是否在于包含大量数字的数字集中(数字集很大)
- 防止缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)
- 邮箱的垃圾邮件过滤、黑名单功能
- 去重:比如爬给定网址的时候对已经爬取过的URL去重
- ……
[1]【原创】不了解布隆过滤器?一文给你整的明明白白!
[2]Bloom Filter in Java using Guava
[3]Bloom Filter
2019-12-17 前端YARN使用
[1]yarn的安装和使用
[2]yarn 环境安装依赖报错解决方法(info fsevents@1.2.7: The platform “win32” is incompatible with this module.)
2019-12-19 Vue项目解决跨域问题
2019-12-19 在服务器部署ES无法访问9200端口的问题
[1]Elasticsearch 安装配置 外网访问 及 后台启动
2019-12-22 Java对象转换,深拷贝
[1]如何优雅的将DTO转化成BO
[2]How to Make a Deep Copy of an Object in Java
[3]Jackson 2 – Convert Java Object to / from JSON
[4]Transform objects with guava
[5]BeanUtils拷贝属性容易忽视的坑
[6]性能优化 —- 避免使用 BeanUtils copy
[7]BeanUtils复制对象属性的坑
[8]对象拷贝类PropertyUtils,BeanUtils,BeanCopier的技术沉淀
[9]Copy properties from one bean into another bean/object (java/ example)
[10]Java对象的深度拷贝实现
[11]FastJSON、Gson和Jackson性能对比
[12]Spring的BeanUtils的copyProperties方法需要注意的点
[13]How to convert from entity to dto using model mapper , with conversion from string to UUID
[14]Entity To DTO Conversion for a Spring REST API
[15]DTO conveter pattern in Spring Boot
[16]Automatically Mapping DTO to Entity on Spring Boot APIs
[17]Apache、Spring、Cglib的beancopy效率对比
[18]你还在用BeanUtils进行对象属性拷贝?
[19]fastjson:SerializerFeature属性使用
[20]fastjson SerializerFeature详解
[21]FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换
[22]java的VO、DTO之间的转换,各种工具类
2019-12-25 将List<Map<String, String>> 合并为Map<String, String>
1 | Map<String, String> mergeMap = list.stream() |
1 | Map<String, String> mergeMap = new HashMap<>(); |
参考:
[1]使用Java8 合并List<Map<String,Object>>为一个Map?
[2]Convert Set<Map.Entry<K, V>> to HashMap<K, V>
2019-12-25 Lombok @Builder与@NoArgsConstructor注解冲突
在一次开发过程中,使用了@NoArgsConstructor和@Builder注解,发现项目启动失败,报错了,而且控制台报的错误是乱码,看不懂。网上搜索后,发现@Builder与@NoArgsConstructor注解是有冲突的,
摘录:
只使用@Builder会自动创建全参构造器。而添加上@NoArgsConstructor后就不会自动产生全参构造器。
Entity上加上@Builder,会默认为类加上全参构造函数,且提供以建造器模式构造对象的方法。但此时因为显示声明了构造器,默认的无参构造器就失效了,就不能通过new Obj()的方式创建对象。这是自然想到加@NoArgsConstructor注解生成无参构造函数以便使用new Obj()方式创建对象,很多框架中都需要反射调用无参构造函数。但是如果显式声明了@NoArgsConstructor,lombok就不会生成全参构造函数,而@Builder中会用到全参构造函数,所以冲突。
解决方案:
- 去掉@NoArgsConstructor,但是有些框架需要通过反射调用无参构造函数,不提供无参构造函数可能会出现其他错误
- 添加@AllArgsConstructor
参考:
[1]Lombok@Builder和@NoArgsConstructor冲突
[2]@Builder @NoArgsConstructor 冲突
2019-12-26 SpringBoot通用service、dao模板
[1]MyBatis通用dao和通用service
[2]spring+mybatis通用dao层、service层的一些个人理解与实现
[3]聊一聊-JAVA 泛型中的通配符 T,E,K,V,?
2019-12-30 Cookie、Session、Token、JWT的区别
[1]傻傻分不清之 Cookie、Session、Token、JWT
2020-01-05 Java 8 Stream 的终极技巧——Collectors 操作
[1]Java 8 Stream 的终极技巧——Collectors 操作
2020-01-06 Java Collection 移除元素的几种方式
2020-01-07 异常处理
2020-01-07 mock测试你的web应用
[1]Spring Boot 2 实战:mock测试你的web应用
2020-01-07 SpringSecurity 相关
[1]Spring Security 实战干货:自定义异常处理
[2]Spring Security 实战干货:纠正对 JSON Web Token 认识的误区
[3]Spring Security 实战干货:路径Uri中的 Ant 风格
[4]Spring Security 实战干货:如何保护用户密码
[5]Spring Security 实战干货:使用 JWT 认证访问接口
2020-01-08 日志体系
2020-01-14 MySQL时间类型存储
- 不要用字符串存储日期时间
- Timestamp 和时区有关。Timestamp 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一个条记录此字段的值会不一样
[1]老生常谈!数据库如何存储时间?你真的知道吗?
2020-01-15 大数据方面
[1]揭秘“撩”大数据的正确姿势:生动示例解说大数据“三驾马车”
2020-01-15 Docker Load 命令的一个注意点
现象:
当代码没有变更,jenkins重新出了有关相同的镜像,虽然时间不一样,但是内容都是一样的。对于新出的镜像包,执行docker load < image.tar.gz命令后,console提示layer already exists,imageId并没有发生变更。
原因:
docker load attempts to load a specified tar archive and will use an existing tag in case the layers/hashes are identical to an already present image. It is not possible to change that behavior in order to get a unique tag or ID - neither on the CLI nor the API.
参考:
[1]Docker load: generate unique ID or tag
2020-01-15 阅读的一些博客
[1]从源码角度剖析 Spring 如何管理 mybatis 事务的?
[2]程序员笔记|编写高性能的Java代码需要注意的4个问题
[3]疫苗:JAVA HASHMAP的死循环
[4]程序员笔记|常见的Spring异常分析及处理
[5]从1+1=2来理解Java字节码
[6]Java 8系列之重新认识HashMap
[7]Time Complexity of Java Collections
2020-01-15 ElasticSearch
2020-01-22 阅读的一些文章
[1]SpringBoot有啥高科技?是怎么做到XML零配置的?
[2]【译】和整洁代码说再见
[3]机器学习基本概念
[4]Time Complexity of Java Collections
[5]Java 8系列之重新认识HashMap
[6]解锁新姿势:探讨复杂的 if-else 语句“优雅处理”的思路
2020-02-24 数据库 事务 锁 隔离级别等
[1]MySQL的可重复读级别能解决幻读吗
[2]面试官问:请介绍一下MySQL数据库的锁机制?
[3]Mysql锁:灵魂七拷问 有赞团队
[4]再谈Transaction——MySQL事务处理分析
[5]MySQL 事务隔离级别和锁
[6]深入理解Mysql——锁、事务与并发控制
[7]mysql处理高并发,防止库存超卖,秒杀活动
[8]秒杀核心设计(减库存部分)-防超卖与高并发
[9]秒杀场景下mysql减库存逻辑优化
[10]mysql处理高并发防止超买超卖
[11]深入浅出Mysql—锁、事务与并发控制看这篇就够了
[12]如何解决秒杀的性能问题和超卖的讨论
2020-02-26 Java8 方法区 永久代 元空间
[1]Java8内存模型—永久代(PermGen)和元空间(Metaspace)
[2]Java内存模型:方法区,永久代,元空间
[3]Java方法区、永久代、元空间、常量池详解
[4]对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法
2020-02-26 Java类卸载
JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):
- 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
- 加载该类的ClassLoader已经被GC。
- 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法
[1]Java Class卸载与ClassLoader
2020-02-26 Java动态代理 反射
[1]Java提高班(六)反射和动态代理(JDK Proxy和Cglib)
2020-02-26 Java中的锁,MySQL中的锁
MySQL:
InnoDB 行锁实现方式:
- InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。
- InnoDB 这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁!
- 不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。
- 只有执行计划真正使用了索引,才能使用行锁:即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查 SQL 的执行计划(可以通过 explain 检查 SQL 的执行计划),以确认是否真正使用了索引。
- 由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然多个session是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的(后使用这些索引的session需要等待先使用索引的session释放锁后,才能获取锁)。应用设计的时候要注意这一点。
InnoDB避免死锁:
- 为了在单个InnoDB表上执行多个并发写入操作时避免死锁,可以在事务开始时通过为预期要修改的每个元组(行)使用SELECT … FOR UPDATE语句来获取必要的锁,即使这些行的更改语句是在之后才执行的。
- 在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁、更新时再申请排他锁,因为这时候当用户再申请排他锁时,其他事务可能又已经获得了相同记录的共享锁,从而造成锁冲突,甚至死锁
- 如果事务需要修改或锁定多个表,则应在每个事务中以相同的顺序使用加锁语句。在应用中,如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会
- 通过SELECT … LOCK IN SHARE MODE 获取行的读锁后,如果当前事务再需要对该记录进行更新操作,则很有可能造成死锁。
- 改变事务隔离级别
如果出现死锁,可以用 SHOW INNODB STATUS 命令来确定最后一个死锁产生的原因。 返回结果中包括死锁相关事务的详细信息,如引发死锁的 SQL 语句,事务已经获得的锁,正在等待什么锁,以及被回滚的事务等。据此可以分析死锁产生的原因和改进措施。
[1]不可不说的Java“锁”事
[2]MySQL数据库的锁机制
[3]MySQL锁总结
2020-02-27 Java8 JVM CodeCache
- CodeCache是热点代码的暂存区,经过即时编译器编译的代码会放在这里,它存在于堆外内存。除了JIT编译的代码之外,Java所使用的本地方法代码(JNI)也会存在CodeCache中。
- JVM内部会先尝试解释执行Java字节码,当方法调用或循环回边达到一定次数时,会触发即时编译,将Java字节码编译成本地机器码以提高执行效率。这个编译的本地机器码是缓存在CodeCache中的,如果有大量的代码触发了即时编译,而且没有及时GC的话,CodeCache就会被填满。
- 一旦CodeCache被填满,已经被编译的代码还会以本地代码方式执行,但后面没有编译的代码只能以解释执行的方式运行。
[1]jvm——CodeCache
[2]java codeCache
[3]深入剖析Java即时编译器(上)
2020-03-07 优化if/else
2020-03-10 Java中Wait、Sleep和Yield方法的区别
2020-03-22 MySQL中varchar存储汉字
[1]一篇文章看懂mysql中varchar能存多少汉字、数字,以及varchar(100)和varchar(10)的区别