构建类型安全的SQL查询

Advanced Spring Data JPA - Specifications and Querydsl

Querying JPA document

querydsl jpa example

1
querysql
很早之前了解过,当时没有看到他的价值,最近在写某业务系统的分页查询过程中,看到基于
1
Specifications
写的复杂查询语句,有点乱,感觉有点点不爽。

jpa 提供了

1
Metamodel
,但是
1
Specifications
难用,生成的语法糖也难用。

下面列出几种在spring-data-jpa中使用查询的例子:

###1.使用querydsl:

1
2
3
4
5
6
7
 public List<SchedulerRule> findByOther(String other) {
	BooleanBuilder builder = new BooleanBuilder();
	builder.or(schedulerRule.memo.containsIgnoreCase(other));
	builder.or(schedulerRule.properties.containsIgnoreCase(other));
	builder.or(schedulerRule.dGroup.containsIgnoreCase(other));
	return new JPAQuery(em).from(schedulerRule).where(builder).orderBy(schedulerRule.id.asc()).list(schedulerRule);
  }

###2.使用原生sql:

1
2
3
4
5
6
public List<SchedulerRule> findByOther(String other) {
    return (List<SchedulerRule>) em
        .createNativeQuery(
            "select * from  scheduler_rule where  memo LIKE :other OR properties LIKE :other OR dGroup LIKE :other order by id",
            SchedulerRule.class).setParameter("other", "%" + other + "%").getResultList();
}

###3.使用

1
@Query
:

1
2
@Query("from SchedulerRule as rule where mod(rule.id, :clusterSize)= :mod and rule.status = 'NORMAL'")
List<SchedulerRule> findByClient(@Param("clusterSize") int clusterSize, @Param("mod") int mod);

###4.使用接口命名生成查询语句:

1
Page<SchedulerRule> findByCreater(String creator, Pageable pageable);

在使用querydsl时,通过配置annotation processor可以很方便的完成代码生成工作:

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
 <!--querydsl-->
        <plugin>
            <groupId>com.mysema.maven</groupId>
            <artifactId>apt-maven-plugin</artifactId>
            <version>1.1.0</version>
            <configuration>
                <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>com.mysema.querydsl</groupId>
                    <artifactId>querydsl-apt</artifactId>
                    <version>3.6.0</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>process</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>src/gen/java</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

ActiveJPA——针对JPA的活动记录模式

http://www.infoq.com/cn/articles/ActiveJPA

活动记录模式在使用上来说,还是很happy的。但是造成的问题是:1.

1
entity
1
DO
耦合在一起了,如果业务复杂,还是老老实实的
1
DDD
吧。2.复杂的查询可能还是需要借助
1
DAO
。如果自己来实现,考虑上关系映射,最后就是活脱脱的一个hibernat出来了。这个框架借助
1
JPA
的能力,简单的实现了活动记录模式。

作者通过

1
java instrument api
+
1
javassit
来生成便于使用的静态方法(不需要提供类型信息)。

用betamax mock掉外部http/https依赖

http://freeside.co/betamax/

1
betamax
在你的应用和外部应用之间架起了proxy.他会录制第一次请求,在本地文件系统中生成
1
Tape
,后续的请求就不会调用目标服务了。我们可以把
1
tape
存放在
1
VCS
中,也可以编辑此文件,满足特殊需求。

Building a Robust and Secure Web Application With Velocity

http://wiki.apache.org/velocity/BuildingSecureWebApplications

这篇文章很老了,但是很值得参考下。

###Best Practices In Building A Secure, Robust Velocity Web Application

  1. Review all context references for unwanted methods.

    不要在Context中放入能改变程序状态的引用。

  2. Encode HTML special characters to avoid cross-scripting vulnerabilities.

    可以通过

    1
    EscapeHtmlReference
    
    对符合特定模式的引用进行过滤。

  3. Use an up-to-date and properly configured app server.

    里面提到通过

    1
    Java Security Manager 
    
    来限制应用的行为。这也是一种不错的方式,只是灵活性不好。可以采用findbugs来检查静态代码,再控制好上传的文件/对系统的直接调用就ok了。

  4. Configure Velocity for production use.

    创建

    1
    EventCartridge
    
    1
    Event Handlers
    
    来捕获异常,并记录进日志。这个工作在
    1
    com.yjf.common.util.Velocitys
    
    里面是做了的。但是spring mvc集成 velocity可以做下。提前发现异常(上次CRSF过滤器配置出错导致的页面乱了)。

##jello–Front End Integrated Solution for J2EE Velocity https://github.com/fex-team/jello

http://106.186.23.103:8080/

使用velocity的同学可以关注下:jello针对服务端为 JAVA + Velocity 的前端集成解决方案。为优化前端开发效率而生,提供前后端开发分离、自动性能优化、模块化开发机制等功能。

模板技巧部分文档适合学习velocity的同学看看。

##模板引擎的选择

关于thymeleaf的性能:http://forum.thymeleaf.org/Performance-issue-td3722763.html 模式freemarker性能最强,thymeleaf性能差距太大

比较JVM上的模板引擎: http://www.slideshare.net/jreijn/comparing-templateenginesjvm

thymeleaf的优点主要在和前端结合起来很不错,前端切完图,然后加上动态数据的部分就ok了。页面不需要服务端也能渲染出来。

CPU Flame Graphs

http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

java里可以很方便的通过

1
jvisualvm
来采样性能数据,然后分析每个线程栈中比较费时的cpu操作.java以外的程序,通过cpu火焰图来分析性能问题,很直观(比较起来,jvisualvm的cpu sample report没有cpu火焰图直观).

生成的

1
svg
报告中,
1
y轴
可以理解为调用栈层次,越大调用层次越深.
1
x轴
中的长度是调用占用时间比.

1
CPU Flame Graphs
生成过程需要三步:

  1. 采样性能数据(perf, DTrace, SystemTap, and ktap)
  2. 转换性能数据
  3. 利用性能数据生成
    1
    svg
    
    报告

协程

http://niusmallnan.github.io/_build/html/_templates/openstack/coroutine_usage.html http://www.dongliu.net/post/5906310176440320

协程是纯软件实现的多任务调度,在软件层面实现任务的保持和恢复.传统的用多线程的方式来实现任务调度,在高并发场景下,CPU创建开销和CPU上下文切换的开销太大.使用协程,任务调度有程序来调度,不涉及到cpu线程切换和cpu大量创建线程,性能会快不少.

在使用协程时,所有的I/O都需要使用异步I/O,不然性能会大打折扣.

在协程中,不同的执行单元之间通信可以采用共享内存或者消息机制.由于共享内存又会引入共享资源的同步,推荐采用消息机制.

基于线程与基于事件的并发编程之争

http://www.jdon.com/46921

基于线程的并发变成带来了很多问题,很难写出高性能的程序。协程和Actor模型也许可以考虑用来降低CS的开销。

Linux Troubleshooting, Part I: High Load

http://www.linuxjournal.com/magazine/hack-and-linux-troubleshooting-part-i-high-load

10月25(This is my big day)日凌晨线上某系统出现

1
load
很高的问题,我当时排查问题的思路和这篇文章类似.简单总结下:

1
load
,系统负载,可以理解为现在等待cpu处理的任务数.如何衡量
1
high
呢?这个和cpu核心数有关系,8核cpu,load为8,这个也不能称之为high.

造成high load的原因一般有:

  • CPU-bound load

    某些任务太耗cpu了,导致high load.这个通过看top就能看出来.如果

    1
    top
    
    命令中的
    1
    xx%wa
    
    很高,说明这些任务都在等待去了.

  • load caused by out of memory issues

    由于内存不足,linux在使用swap了,导致high load.这个通过

    1
    free
    
    很容易看出来.

  • I/O-bound load

    iostat/iotop(需安装)都很容易发现原因所在.

我偏向于使用

1
vmstat
,用了它,什么都可以看到了.很悲剧的是,这台线上服务器一切正常.服务器重启后,负载一直很低.服务器重启后,一切都正常了.

The Best Plugins for Sublime Text

http://ipestov.com/the-best-plugins-for-sublime-text/

可以把sublime武装成ide的插件.

ibatis和mybatis共存

如果先加载ibatis的jar,会遇到

1
java.lang.reflect.MalformedParameterizedTypeException
异常.需要让ibatis后加载.可以修改
1
ibatis
依赖的
1
artifactId
,比如改为
1
zibatis

MySQL 加锁处理分析

http://hedengcheng.com/?p=771

这篇文章从mysql数据库原理角度来分析锁,很透彻,很深刻.

比如对于一条简单的sql语句:

1
delete from test where id = ?;

如果id是主键/非空的唯一索引,不会出现gap锁.如果是非索引列,直接锁表(这个太恶心了,因为server和存储引擎分离导致的);如果是非唯一的索引,事务隔离级别是read commit,锁定选取的数据.如果是repeatable read,为了防止幻读,gap lock出现了)

##面向程序员的数据库访问性能优化法则 http://blog.csdn.net/yzsind/article/details/6059209

这篇文章很系统的介绍了程序员应该掌握的数据库优化知识. 首先根据硬件相关知识介绍各种硬件的访问延时/带宽指标:

通过对上面的指标分析,自然得出优化的层次:

  1. 减少数据访问(减少磁盘访问)

    • 正确创建/使用索引
    • 只通过索引访问数据(索引节点中存有数据,通过索引就能拿到数据最高效)
    • 根据查询计划优化索引
    • 一个表上的索引不能太多,会增加修改操作IO.
  2. 返回更少数据(减少网络传输或磁盘访问)

    • 分页(通过rowid分页的方式减少IO,前提是where/order子句都要在索引上)
    • 只返回需要的字段(别使用select *,带来各种问题,对于我们来说,最头痛的是sql版本兼容性问题.)
  3. 减少交互次数(减少网络传输)

    • batch DML(批量操作走jdbc批量接口)
    • In List(多操作合并,依稀记得mysql驱动里也有这样的做法)
    • 设置Fetch Size(默认fetch size可能不是最优的,需要根据实际情况调整,比如分页查询,一次查询100条,在不OOM的前提下增大此值,减少网络io)
    • 使用存储过程(这个得看场景)
    • 使用ResultSet游标处理记录(这一点往往被忽略掉,使用mybatis的RowHandler来解决问题)
  4. 减少服务器CPU开销(减少CPU及内存开销)

    • 使用绑定变量(mysql仅仅支持硬解析,参考)
    • 合理使用排序
  5. 利用更多资源(增加资源)