学习总结 2017-10

前言

记录10月份学习记录,不定期更新

2017-10-05

windows查看端口占用和杀进程

查看端口占用
netstat -aon|findstr "49157"

找到进程pid后,杀掉该进程

taskkill /pid 12188 /f

2017-10-10

Java中的十个"单行代码编程"(One Liner)

本文列举了十个使用一行代码即可独立完成(不依赖其他代码)的业务逻辑,主要依赖的是Java8中的Lambda和Stream等新特性以及try-with-resources、JAXB等。

对列表/数组中的每个元素都乘以2

 // Range是半开区间
 int[] ia = range(1, 10).map(i -> i * 2).toArray();
 List<Integer> result = range(1, 10).map(i -> i * 2).boxed().collect(toList());

计算集合/数组中的数字之和

 range(1, 1000).sum();
 range(1, 1000).reduce(0, Integer::sum);
 Stream.iterate(0, i -> i + 1).limit(1000).reduce(0, Integer::sum);
 IntStream.iterate(0, i -> i + 1).limit(1000).reduce(0, Integer::sum);

验证字符串是否包含集合中的某一字符串

final List<String> keywords = Arrays.asList("brown", "fox", "dog", "pangram");
final String tweet = "The quick brown fox jumps over a lazy dog. #pangram http://www.rinkworks.com/words/pangrams.shtml";

keywords.stream().anyMatch(tweet::contains);
keywords.stream().reduce(false, (b, keyword) -> b || tweet.contains(keyword), (l, r) -> l || r);

读取文件内容

原作者认为try with resources也是一种单行代码编程。

 try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
   String fileText = reader.lines().reduce("", String::concat);
 }

 try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
   List<String> fileLines = reader.lines().collect(toCollection(LinkedList<String>::new));
 }

 try (Stream<String> lines = Files.lines(new File("data.txt").toPath(), Charset.defaultCharset())) {
   List<String> fileLines = lines.collect(toCollection(LinkedList<String>::new));
 }

输出歌曲《Happy Birthday to You!》 - 根据集合中不同的元素输出不同的字符串

 range(1, 5).boxed().map(i -> { out.print("Happy Birthday "); if (i == 3) return "dear NAME"; else return "to You"; }).forEach(out::println);

过滤并分组集合中的数字

 Map<String, List<Integer>> result = Stream.of(49, 58, 76, 82, 88, 90).collect(groupingBy(forPredicate(i -> i > 60, "passed", "failed")));

获取并解析xml协议的Web Service

FeedType feed = JAXB.unmarshal(new URL("http://search.twitter.com/search.atom?&q=java8"), FeedType.class);
JAXB.marshal(feed, System.out);

获得集合中最小/最大的数字

 int min = Stream.of(14, 35, -7, 46, 98).reduce(Integer::min).get();
 min = Stream.of(14, 35, -7, 46, 98).min(Integer::compare).get();
 min = Stream.of(14, 35, -7, 46, 98).mapToInt(Integer::new).min();

 int max = Stream.of(14, 35, -7, 46, 98).reduce(Integer::max).get();
 max = Stream.of(14, 35, -7, 46, 98).max(Integer::compare).get();
 max = Stream.of(14, 35, -7, 46, 98).mapToInt(Integer::new).max();

并行处理

 long result = dataList.parallelStream().mapToInt(line -> processItem(line)).sum();

集合上的各种查询(LINQ in Java)

List<Album> albums = Arrays.asList(unapologetic, tailgates, red);

//筛选出至少有一个track评级4分以上的专辑,并按照名称排序后打印出来。
albums.stream()
  .filter(a -> a.tracks.stream().anyMatch(t -> (t.rating >= 4)))
  .sorted(comparing(album -> album.name))
  .forEach(album -> System.out.println(album.name));

//合并所有专辑的track
List<Track> allTracks = albums.stream()
  .flatMap(album -> album.tracks.stream())
  .collect(toList());

//根据track的评分对所有track分组
Map<Integer, List<Track>> tracksByRating = allTracks.stream()
  .collect(groupingBy(Track::getRating));

2017-10-17

Jackson的@JsonFormat注解日期少一天问题

项目中使用了@JsonFormat来进行格式化日期,却意外发现日期少了一天,
比如数据库存的日期是2017-10-15,转成json则变成了2017-10-14
于是查资料,发现这个注解有个坑,JsonFormat默认是不带时区
解决办法:

@JsonFormat(pattern="yyyy-MM-dd")
 public Date getRegistDate() {
  return this.registDate;
 }

改成

@JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
 public Date getRegistDate() {
  return this.registDate;
 }

加上时区即可,中国是东八区

2017-10-18

mysql如何解决幻读问题

mysql默认的事务隔离级别是repeatable-read,也就是可重复读,按照sql事务标准的话,这个隔壁级别是可以解决脏读和不可重复的问题的,但是不能解决幻读的问题,但是mysql却解决了幻读这个问题,那到底是怎么实现的呢?

官方文档

http://dev.mysql.com/doc/refman/5.0/en/innodb-record-level-locks.html

By default, InnoDB operates in REPEATABLE READ transaction isolation level and with the innodb_locks_unsafe_for_binlog system variable disabled. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows (see Section 13.6.8.5, “Avoiding the Phantom Problem Using Next-Key Locking”).

准备的理解是,当隔离级别是可重复读,且禁用innodb_locks_unsafe_for_binlog的情况下,在搜索和扫描index的时候使用的next-key locks可以避免幻读。

关键点在于,是InnoDB默认对一个普通的查询也会加next-key locks,还是说需要应用自己来加锁呢?如果单看这一句,可能会以为InnoDB对普通的查询也加了锁,如果是,那和序列化(SERIALIZABLE)的区别又在哪里呢?

MySQL manual里还有一段:

13.2.8.5. Avoiding the Phantom Problem Using Next-Key Locking (http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html)

To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking.

You can use next-key locking to implement a uniqueness check in your application: If you read your data in share mode and do not see a duplicate for a row you are going to insert, then you can safely insert your row and know that the next-key lock set on the successor of your row during the read prevents anyone meanwhile inserting a duplicate for your row. Thus, the next-key locking enables you to “lock” the nonexistence of something in your table.

我的理解是说,InnoDB提供了next-key locks,但需要应用程序自己去加锁。manual里提供一个例子:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

SHOW ENGINE INNODB STATUS 来查看是否给表加上了锁。

mySQL manual里对可重复读里的锁的详细解释:

http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read

For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE),UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition. For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it. For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key (gap plus index-record) locks to block insertions by other sessions into the gaps covered by the range.

实验

一致性读和提交读,先看实验,实验四:

t Session A                      Session B
|
| START TRANSACTION;             START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|                                INSERT INTO t_bitfly
|                                VALUES (2, 'b');
|                                COMMIT;
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
|
| SELECT * FROM t_bitfly LOCK IN SHARE MODE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly FOR UPDATE;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| |  2 | b     |
| +----+-------+
|
| SELECT * FROM t_bitfly;
| +----+-------+
| | id | value |
| +----+-------+
| |  1 | a     |
| +----+-------+
v

如果使用普通的读,会得到一致性的结果,如果使用了加锁的读,就会读到“最新的”“提交”读的结果。

本身,可重复读和提交读是矛盾的。在同一个事务里,如果保证了可重复读,就会看不到其他事务的提交,违背了提交读;如果保证了提交读,就会导致前后两次读到的结果不一致,违背了可重复读。

可以这么讲,InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。

http://dev.mysql.com/doc/refman/5.0/en/innodb-consistent-read.html

If you want to see the “freshest” state of the database, you should use either the READ COMMITTED isolation level or a locking read:
SELECT * FROM t_bitfly LOCK IN SHARE MODE;

------

mvcc

在官方文档中写道

http://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html

A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time. The query sees the changes made by transactions that committed before that point of time, and no changes made by later or uncommitted transactions. The exception to this rule is that the query sees the changes made by earlier statements within the same transaction. This exception causes the following anomaly: If you update some rows in a table, a SELECT sees the latest version of the updated rows, but it might also see older versions of any rows. If other sessions simultaneously update the same table, the anomaly means that you might see the table in a state that never existed in the database.

一致性读是通过 MVCC 为查询提供了一个基于时间的点的快照。这个查询只能看到在自己之前提交的数据,而在查询开始之后提交的数据是不可以看到的。一个特例是,这个查询可以看到于自己开始之后的同一个事务产生的变化。这个特例会产生一些反常的现象

If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction. You can get a fresher snapshot for your queries by committing the current transaction and after that issuing new queries.

在默认隔离级别REPEATABLE READ下,同一事务的所有一致性读只会读取第一次查询时创建的快照

结论

结论:MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是next-key locks。

MySQL MVCC简介

什么是MVCC

MVCC是一种多版本并发控制机制。

MVCC是为了解决什么问题?

大多数的MYSQL事务型存储引擎,如,InnoDB,Falcon以及PBXT都不使用一种简单的行锁机制.事实上,他们都和MVCC–多版本并发控制来一起使用.
大家都应该知道,锁机制可以控制并发操作,但是其系统开销较大,而MVCC可以在大多数情况下代替行级锁,使用MVCC,能降低其系统开销.

MVCC实现

MVCC是通过保存数据在某个时间点的快照来实现的. 不同存储引擎的MVCC. 不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制.

具体实现分析

下面,我们通过InnoDB的MVCC实现来分析MVCC使怎样进行并发控制的.
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间。这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),没开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID.下面看一下在REPEATABLE READ隔离级别下,MVCC具体是如何操作的.

简单的小例子

create table zhang( 
id int primary key auto_increment, 
name varchar(20));

假设系统的版本号从1开始.

INSERT

InnoDB为新插入的每一行保存当前系统版本号作为版本号.
第一个事务ID为1;

start transaction;
insert into yang values(NULL,'zhang') ;
insert into yang values(NULL,'guo');
insert into yang values(NULL,'ji');
commit;

对应在数据中的表如下(后面两列是隐藏列,我们通过查询语句并看不到)

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 undefined
2 guo 1 undefined
3 ji 1 undefined

SELECT

InnoDB会根据以下两个条件检查每行记录:
a.InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
b.行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
只有a,b同时满足的记录,才能返回作为查询结果.

DELETE

InnoDB会为删除的每一行保存当前系统的版本号(事务的ID)作为删除标识.
看下面的具体例子分析:
第二个事务,ID为2;

start transaction;
select * from zhang;  //(1)
select * from zhang;  //(2)
commit; 

假设1

假设在执行这个事务ID为2的过程中,刚执行到(1),这时,有另一个事务ID为3往这个表里插入了一条数据;
第三个事务ID为3;

start transaction;
insert into zhang values(NULL,'tian');
commit;

这时表中的数据如下:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 undefined
2 guo 1 undefined
3 ji 1 undefined
4 tian 3 undefined

然后接着执行事务2中的(2),由于id=4的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于等于当前事务ID的数据行,所以id=4的数据行并不会在执行事务2中的(2)被检索出来,在事务2中的两条select 语句检索出来的数据都只会下表:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 undefined
2 guo 1 undefined
3 ji 1 undefined

假设2

假设在执行这个事务ID为2的过程中,刚执行到(1),假设事务执行完事务3后,接着又执行了事务4;
第四个事务:

start transaction;  
delete from zhang where id=1;
commit;

此时数据库中的表如下:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 4
2 guo 1 undefined
3 ji 1 undefined
4 tian 3 undefined

接着执行事务ID为2的事务(2),根据SELECT 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,而id=4的行上面已经说过,而id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务2的(2)select * from yang也会把id=1的数据检索出来.所以,事务2中的两条select 语句检索出来的数据都如下:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 undefined
2 guo 1 undefined
3 ji 1 undefined

UPDATE

InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间.

假设3

假设在执行完事务2的(1)后又执行,其它用户执行了事务3,4,这时,又有一个用户对这张表执行了UPDATE操作:
第5个事务:

start  transaction;
update yang set name='Guo' where id=2;
commit;

根据update的更新原则:会生成新的一行,并在原来要修改的列的删除时间列上添加本事务ID,得到表如下:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 4
2 guo 1 5
3 ji 1 undefined
4 tian 3 undefined
5 Guo 5 undefined

继续执行事务2的(2),根据select 语句的检索条件,得到下表:

id name 创建时间(事务ID) 删除时间(事务ID)
1 zhang 1 undefined
2 guo 1 undefined
3 ji 1 undefined

还是和事务2中(1)select 得到相同的结果.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容