Multi-Tenancy in JPA
EclipseLink
EclipseLink支持多种多租户(multi-tenancy)实现。 主要通过@Multitenant等相关的annotation来提供对multi-tenancy的支持。
public @interface Multitenant {
MultitenantType value() default MultitenantType.SINGLE_TABLE;
boolean includeCriteria() default true;
}
@Multitenant
支持SINGLE_TABLE
和TABLE_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
这是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属性参考手册
CSS Reference - A free visual guide to the most popular CSS properties.
一个可视化的CSS属性参考手册。 可以看不同的属性值对应的视觉效果。 如果需要更详细的参考,还可以点击页面上的MDN链接。
书籍推荐:The Linux Programming Interface
The Linux Programming Interface,💯。 亚马逊上的评价98%为五星,2%为四星。即便不做Linux开发,读一遍对于了解Linux还是非常有帮助的。
Java代码性能调优
Java performance tuning tips or everything you want to know about Java performance in 15 minutes
关于Java性能调优的一篇文章,其内容是java-performance.info上所有文章的归纳总结。 主要侧重于Java代码本身的调优,不涉及JVM参数。 推荐一看。
避开Java基准测试中的陷阱
Avoiding Benchmarking Pitfalls on the JVM
基准测试看似简单,但是由于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
Aleksey Shipilëv: One Stop Page
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.
Mkyong.com每月有六百万的Page View
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来存储密码
Why is char[] preferred over String for passwords in Java?
为什么Java Swing用char[]
来存储密码,而不是String
?
因为String
是不可变的(immutable)。
这意味着在String
对象被垃圾回收前,密码会一直存在于内存中。
(虽然可以通过反射来修改String
对象的field的访问权限,进而修改String
对象。)
使用char[]
来存储密码的好处是使用后可以马上抹掉char[]
的内容。
安全总是相对的。一种可能性(取决于JVM实现)是在抹掉char[]
之前发生了GC,移动了char[]
对象
(比如从Eden移动到Survivor),使得老的char[]
还驻留在内存里。
还有一点要注意的是不要在log里(无意地)打印敏感信息,比如密码等。