Multi-Tenancy in JPA

2016 Nov 8

EclipseLink支持多种多租户(multi-tenancy)实现。 主要通过@Multitenant等相关的annotation来提供对multi-tenancy的支持。

public @interface Multitenant {
    MultitenantType value() default MultitenantType.SINGLE_TABLE;
    boolean includeCriteria() default true;
}

@Multitenant支持SINGLE_TABLETABLE_PER_TENANT等方式(还有VPD)。 SINGLE_TABLE表示多个租户共用一张表;一般这种方式单租户的成本比较低。 TABLE_PER_TENANT表示不同租户的表是隔离的。隔离的方式有不同的租户的表有不同的前缀/后缀或者放在不同的schema里。

配置好相关的annotation后,查询、更新或者删除时EclipseLink会自动帮你在query里拼接上tenant信息。 在某些情况下,自动拼出来的query也会有问题。比如EclipseLink 2.6.2在multi-tenancy下的left join就有问题。 EclipseLink会在left join的where子句里拼接上tenant相关的条件,

SELECT t0.ID, t1.ID FROM CURRENCY t0 LEFT OUTER JOIN EXCHANGERATE t1 
  ON (((t1.currencyId = t0.ID) AND (t1.RATEDATE >= ?)) AND (t1.RATEDATE <= ?)) 
  WHERE (((t0.STATUS = ?) AND (t0.TENANT_ID = ?)) AND (t1.TENANT_ID = ?))

(t1.TENANT_ID = ?)会使得left join“退化”成inner join。

对于这种问题可以用native query来避免EclipseLink对query的修改;

Optional in Java 8

2016 Nov 6

这是Java SE 8 for the Really Impatient的一篇笔记。

一个Optional对象要么有内容(contain a non-null value),要么其内容为空。 Optional如果使用不当并不能体现它的优势。比如,

// 下面两段代码都可能抛异常
Optional<T> optionalValue = ...; 
optionalValue.get().someMethod(); 

T value = ...; 
value.someMethod();

// 下面两段代码都有繁琐的if判断
if (optionalValue.isPresent()) 
  optionalValue.get().someMethod();
  
if (value != null) 
  value.someMethod();

Optional定义了一些方法,这些方法可以在一个Optional对象有内容时才执行某段代码, 或者没有内容时提供替代性的值。 使用这些方法,才能让Optional发挥优势,使代码远离NullPointerException或者繁琐的null值判断。

// 如果Optional对象里有非null值,则执行某个操作;否则什么也不做
optionalValue.ifPresent(v -> results.add(v));
// 如果Optional对象里有非null值,那么把这个值赋给result;否者把"foo"赋给result
String result = optionalString.orElse("foo");
String result = optionalString.orElseGet(() -> SOME_MAP.get("key"));
String result = optionalString.orElseThrow(NoSuchElementException::new);

Optional对象可以通过下面的方法创建,

可视化的CSS属性参考手册

2016 Nov 5

一个可视化的CSS属性参考手册。 可以看不同的属性值对应的视觉效果。 如果需要更详细的参考,还可以点击页面上的MDN链接。

书籍推荐:The Linux Programming Interface

2016 Nov 5

The Linux Programming Interface,💯。 亚马逊上的评价98%为五星,2%为四星。即便不做Linux开发,读一遍对于了解Linux还是非常有帮助的。

亚马逊链接豆瓣链接

The Linux Programming Interface

Java代码性能调优

2016 Nov 2

关于Java性能调优的一篇文章,其内容是java-performance.info上所有文章的归纳总结。 主要侧重于Java代码本身的调优,不涉及JVM参数。 推荐一看。

避开Java基准测试中的陷阱

2016 Nov 2

基准测试看似简单,但是由于JVM会在运行时做优化,可能使得基准测试的结果失去意义。

比如JVM如果“看到”接口只有一种实现时,会对接口方法的调用做优化。 如果在后续运行中“看到”很多的接口实现时,则会抛弃掉之前的优化。 这会导致对第二个接口实现的benchmark结果变得不准确。 其它JVM优化手段还有dead-code elimination、constant folding等等。

所谓基准测试,意味着有baseline,有对比,JVM的优化会导致对比的某一方得到了“不公平的”优待,使得对比的结果失去了意义。

文章推荐使用jmh来做基准测试。

it was developed as part of the OpenJDK project

JMH is popular for writing microbenchmarks, that is, benchmarks that stress a very specific piece of code. …

博客推荐:Aleksey Shipilëv

2016 Nov 2

Aleksey Shipilëv的博客。

Aleksey is working on Java performance for 10+ years. Today he is employed by Red Hat, where he does OpenJDK development and performance work.

博客推荐:Java Annotated Monthly

2016 Nov 2

来自IntelliJ IDEA团队的Java社区每月动态汇编。💯

Mkyong.com每月有六百万的Page View

2016 Nov 1

Google “java xxx tutorial”时,mkyong.com常常会出现在搜索结果页中。 2013年的时候,mkyong.com就达到了每月三百万+的page view。 而根据siteworthtraffic的估算,mkyong.com当前的每月page view超过六百万,估算的广告收入每月超过六千美元。 mkyong.com的流量80%来自于搜索。

另一个和mkyong.com类似的网站Java教程网站jenkov.com,每月大约有一百五十万的page vew,估算的广告收入每月大约为一千五百美元。

一些感想,

  • 有质量的、系统性的内容。好的内容可以一定程度上带来流量。
  • 发布时间早,相关的内容少,搜索排名高,进而被引用也多,产生良性循环,持续带来流量。

为什么推荐用char[]而不是String来存储密码

2016 Nov 1

为什么Java Swing用char[]来存储密码,而不是String

因为String是不可变的(immutable)。 这意味着在String对象被垃圾回收前,密码会一直存在于内存中。 (虽然可以通过反射来修改String对象的field的访问权限,进而修改String对象。) 使用char[]来存储密码的好处是使用后可以马上抹掉char[]的内容。

安全总是相对的。一种可能性(取决于JVM实现)是在抹掉char[]之前发生了GC,移动了char[]对象 (比如从Eden移动到Survivor),使得老的char[]还驻留在内存里。

还有一点要注意的是不要在log里(无意地)打印敏感信息,比如密码等。